跳到主要内容

为API添加七牛云私有化防护的踩坑记录

· 阅读需 4 分钟

起因:一个简单的防盗需求

我的数据库API托管了不少图片资源,之前用的是七牛云的公开空间,配合Referer防盗链。说实话,一开始觉得挺简单,配置一下白名单就行了,能防止别人盗链嘛。

但很快就遇到了问题:

本地开发的时候图片全挂了

因为本地开发用的是 localhost,Referer是 http://localhost,根本不在白名单里。每次要测试图片显示,都得先上传到服务器或者临时关闭防盗链,说实话是比较麻烦的。

Referer防盗链只是君子协议,技术上很容易被伪造,安全性也不够高。所以我就想,要不干脆上私有空间算了?

第一坑:私有空间的认知误区

一开始我天真的以为,只要把七牛云的空间设置为"私有",然后按照文档生成带token的URL就行了。结果:

{"error":"download token not specified"}

我反复检查:

  • Bucket是不是私有?
  • AK/SK对不对?
  • URL格式对不对?

就是不行!

第二坑:自己实现签名算法的"正确"方式

我按照网上找到的教程,用PHP实现了七牛云的签名算法:

// 我的实现
$path = parse_url($url, PHP_URL_PATH);
$baseStr = $path . '?e=' . $deadline;
$sign = hash_hmac('sha1', $baseStr, $secretKey, true);
$encodedSign = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($sign));
$token = $accessKey . ':' . $encodedSign;

看起来很完美对吧?完全不对!

第三坑:Base64编码的填充字符问题

后来我用Python官方SDK生成了一个测试URL,发现了一个关键差异:

Python生成的token末尾有 = 我的实现把 = 全移除了

这就是问题所在!七牛云的签名需要保留Base64末尾的填充字符。

// ❌ 错误:移除了 =
$find = ['+', '/', '='];
$replace = ['-', '_', ''];

// ✅ 正确:只替换+和/,保留=
return strtr(base64_encode($data), '+/', '-_');

修复后,还是403...

第四坑:签名对象的差异(最关键的一步)

这个坑踩得最深。我以为只对URL的path部分签名就行了,结果发现官方SDK的实现完全不同:

我的实现:

// 只对path签名
$baseStr = '/static/232.jpg?e=1772817970';
$token = sign($baseStr);
// 最终URL:/static/232.jpg?e=xxx&token=xxx ❌

官方SDK的实现:

// 对整个URL签名!
$urlWithDeadline = 'https://open.xinyuu.cn/static/232.jpg?e=1772817970';
$token = sign($urlWithDeadline);
// 最终URL:...jpg?e=xxx&token=xxx ✅

区别大了去了!官方SDK是:

  1. 在原URL后面追加 ?e=deadline&e=deadline
  2. 对整个URL字符串进行签名(不是只对path!)
  3. 使用 &token= 连接(不是 ?token=

这就是为什么一直403的原因!

修复后的实现完全按照官方SDK的逻辑:

public static function privateDownloadUrl($url, $expires = null) {
$deadline = time() + $expires;

// 在URL后添加 e 参数
$pos = strpos($url, '?');
if ($pos !== false) {
$url .= '&e=';
} else {
$url .= '?e=';
}
$url .= $deadline;

// 对整个URL进行签名
$signData = self::signData($url);

// 用 & 连接token
return $url . '&token=' . $signData;
}

测试通过!图片终于能正常显示了!🎉

经验总结

给想要实现同样功能的伙伴们:

  1. 先跑通官方SDK 不要自己写实现,先用Python或PHP官方SDK测试,确保密钥、空间配置都没问题。

  2. 仔细对比实现差异 特别是:

    • 签名的对象是什么(path还是完整URL?)
    • Base64编码是否保留填充字符
    • URL连接符是 ? 还是 &
  3. 官方文档要看源码 有时候文档描述不够清楚,直接看官方SDK的源码最可靠。

  4. 分步调试很重要 我创建了很多调试工具,逐步验证每个环节,最后才定位到问题所在。

关于Token有效期:

我设置的是3600秒(1小时),这个可以根据实际需求调整:

  • 安全要求高:设置短一点(如1800秒)
  • 用户体验优先:设置长一点(如7200秒)

每次API请求都会生成新的token,所以过期后会自动刷新。


参考资料:

XinyuuDB数据引用声明

· 阅读需 3 分钟

本项目在采集番剧信息时,主要依据以下数据源进行整合与校对。各数据源按其可信度、数据完整性与更新频率,分为“首选”与“备选”两类,并在实际抓取过程中设有自动降级机制,确保数据获取的稳定性与准确性。

目前仍处于起步发展阶段。我们致力于构建一个结构清晰、来源可信、易于维护的番剧信息库,并为开发者、动漫爱好者及相关平台提供可靠的数据支持。

我会在每季度新番放送开始后的一个月进行下一季度的第一次数据采集,并在此后的每周进行数据更新。同时把当前季度的番剧导出汇总到历史统计中:

https://history.xinyuu.cn/statistics

浏览数据库条目:

https://db.xinyuu.cn/workerspace

数据引用优先级说明

数据源主要动作优先级
Bangumi 番组计划
bgm.tv
获取番剧基础信息:
- 标题(中文、日文)
- 简介(日文)
- STAFF 信息(日文)
- 封面图
- 角色与声优信息(日文)
首选
Deepseek
chat.deepseek.com
上传并翻译以下内容:
- 标题(日文)
- 简介(日文)
- STAFF 信息(日文)
- 角色与声优信息(日文)
首选
H萌
xf.hmacg.cn
获取番剧基础信息:
- 标题(中文、日文)
- 简介(中文)
- STAFF 信息(中文)
- 封面图
角色与声优信息(中文)
首选
Yuc's Anime List
yuc.wiki
用于信息校准与补充:
- 校准播出平台信息
- 获取广播状态与时间
- 获取封面图(备选来源)
备选
夏日幻听MCE
bilibili.com
获取番剧相关视频信息:
- PV(宣传视频)信息
首选
糖心蛋字幕组
bilibili.com
获取番剧相关视频信息:
- PV(宣传视频)信息
备选
游戏动漫君V
bilibili.com
获取番剧相关视频信息:
- PV(宣传视频)信息
备选

关于 H萌

XinyuuDB的诞生离不开H萌新番表的数据支持,我们非常欢迎社区成员参与数据的校对、补充与结构优化。如果您对当前数据格式有改进建议,或希望利用本项目的数据进行二次开发,欢迎通过以下方式联系我们并加入协作:

从零开始实现QSL卡片插件 | 我的业余无线电数字化之旅

· 阅读需 24 分钟

一、需求分析与业务场景

1.1 业务场景梳理

  • 传统 QSL 卡片:记录双方呼号、时间、频率、模式、信号报告等基础通联信息。
  • 眼球通联卡片:用于线下见面交流的确认与记录。
  • 比赛日志卡片:在竞赛环境中记录得分、交换信息、成绩等结构化数据。
  • 卫星通联卡片:涉及卫星名称、上下行频率、轨道参数等专业数据。

1.2 功能需求清单

  1. 多类型卡片支持:涵盖上述四种主要场景,预留扩展能力。
  2. 数据可视化与检索:支持结构化展示、多维度筛选与实时搜索。
  3. 历史数据迁移:兼容旧有数据格式,实现平滑升级。
  4. 国际化与国家识别:自动识别通联国家/地区并展示对应国旗与元数据。
  5. 响应式与主题化:适配多端屏幕,支持明暗主题切换。
  6. 用户体验优化:交互流畅、视觉一致、操作符合直觉。

二、技术选型与架构设计

2.1 技术栈决策

  • 前端框架:React 18,基于函数组件与 Hooks 构建,提升组件复用性与状态管理效率。
  • 样式方案:CSS Modules + Material 3 设计系统,实现样式隔离与现代化视觉语言。
  • 工具链:ES6+ 语法,配合 Vite 构建工具提升开发体验与打包性能。
  • 数据管理:本地状态结合 Context API,满足组件间状态共享需求。

2.2 系统架构图(模块化设计)

QSLCard Plugin
├── 展示层 (Presentation)
│ ├── QSLCard (主容器组件)
│ ├── QSLList (列表布局)
│ └── SearchBar (搜索与过滤)
├── 卡片类型层 (Card Types)
│ ├── StandardQSLCard
│ ├── EyeBallCard
│ ├── ContestCard
│ └── SatelliteCard
├── 工具服务层 (Utilities)
│ ├── dataMigration (数据迁移引擎)
│ └── countryUtils (国家识别服务)
└── 样式资源层 (Styles)
├── 主题变量 (CSS Custom Properties)
└── 卡片类型样式模块

Docusaurus Material 3图片拾色器插件开发教程 | React组件实战指南

· 阅读需 9 分钟

Docusaurus Material 3图片拾色器插件完整开发教程

项目概述与技术亮点

在现代网页设计和开发中,颜色提取是一个常见且实用的功能。本教程将详细介绍如何在Docusaurus中创建一个功能完整的图片拾色器插件,该插件具有以下核心特性:

核心功能特点

  • 完全本地化运行:所有操作在浏览器中完成,保护用户隐私
  • Material Design 3设计:采用Google最新设计语言
  • Docusaurus主题集成:与现有主题系统完美融合
  • 响应式设计:完美适配PC端和移动端
  • 无依赖实现:纯原生JavaScript和React实现

技术栈概览

  • Canvas API:获取图片像素颜色数据
  • React Hooks:状态管理和副作用处理
  • CSS Variables:实现主题系统集成
  • File API:处理图片上传和读取

自制五单元U段八木天线教程 | 430MHz业余天线制作指南

· 阅读需 2 分钟

五单元U段八木天线制作完整教程

天线设计原理与参数

本设计基于BG8AMG制图的五单元U段八木天线方案,针对430MHz-440MHz业余频段进行优化。

八木天线设计图

天线结构参数表

振子类型长度振子间隔功能说明
一号引向振子282mmNONE增强方向性
二号引向振子298mm172mm提高增益
三号引向振子298mm172mm优化波束
有源振子322mm99mm馈电点
反射振子335mm146mm反射信号

天线技术规格

基本参数

  • 适用频段:410MHz-460MHz(优化频段:430MHz-440MHz)
  • 天线驻波比:1.2(优秀匹配)
  • 耐受功率:≈25瓦
  • 特性阻抗:50Ω

材料规格

  • 馈线类型:SYV50-3同轴电缆
  • 振子材质:Φ3×0.15mm不锈钢线材
  • 有源振子:Φ3×0.15mm不锈钢
  • 馈电点连接:压接方式
  • 连接方式:卡扣式可拆卸设计

历史版本对比

  • 早期版本:1mm铝线 + 热熔连接
  • 当前版本:不锈钢线材 + 卡扣连接

制作过程详解

中国A类业余无线电台操作证考试指南 | 考点速记与备考技巧

· 阅读需 4 分钟

中国A类业余无线电台操作证考试完整指南

考试政策与法规要点

核心记忆口诀:「三短一长选最长,三场一短选最短,特殊题目特殊记」

无线电管理权限层级

在无线电管理体系中,中央(国家)部门权限高于地方性部门,以下机构在无线电管理中具有重要作用:

  • 中央军委:负责军事无线电管理
  • 国务院:统筹全国无线电管理工作
  • 工信部:具体执行无线电监管职责

经典例题:申请设置业余无线电台应当具备的条件包括:

  • 熟悉无线电管理规定
  • 具备国家规定的操作技术能力
  • 发射设备符合国家技术标准
  • 法律和行政法规规定的其他条件

未来已来 时不我待

· 阅读需 2 分钟

因为很重要,才拼尽全力去模仿。

因为很喜欢,才拼尽全力去学习。

要能互相理解,要能和睦相处,

为了做到这些的林林总总。

所以我突然萌生念头。

就这样,试着把这些经历都记录下来吧!