生产最佳实践
一份上线前的清单。每一条后面都有一次真实踩过的坑——不是凭空想出来的谨慎。
凭据
- 应用密钥只放服务端。 前端要数据就让自己的后端代理。密钥进了浏览器包就等于公开发布。
- 一个产品一个应用。 出事时能单独吊销,用量也能分开看。
- 轮换不需要停机:先铸新密钥、灰度切流、再吊销旧的。每个应用可以同时持有 5 把。
- 代表用户读写就用用户令牌,不要用应用密钥加一个自定义的「user_id」参数——那样的面我们不提供,因为它无法证明是那个用户本人。
客户端契约
- 忽略未知字段。 我们只做加法,你的反序列化不能因为多了一个键就抛异常。
- 容忍开放词表里没见过的取值。
source、platform、语言这些是开放的,switch必须有default。 - 为未知的错误
code准备一个按 HTTPstatus的兜底分支。 注册表会增长。
生成客户端时不要把 schema 编译成
additionalProperties: false的严格类型。我们的 spec 明确声明additionalProperties: true,那是加法演进的前提。
把请求数压下去
| 别这么写 | 改成 |
|---|---|
| 搜索 → 对每条命中打一次详情 | 搜索 → 一次 ids= 批量水合(N+1 → 2) |
| 手里有 VNDB id,先按标题搜再猜 | refs=vndb:v19658 直接反查,最多 100 个一批 |
| 每晚全量重扫目录 | 订 /v2/catalog/changes 增量信道 |
include= 一次要满 18 个块 |
只要这个页面真正渲染的那几块 |
| 给列表页每一项单独请求封面 | include=covers 随列表一起批量水合 |
错误与重试
4xx不重试(429除外)。它是你的请求有 bug,重试一百次也一样。429按Retry-After等,并且加抖动。整点齐发的定时任务会一起撞墙、再一起重试。QUOTA_EXCEEDED不要退避重试——今天没额度了,等待没有意义。5xx指数退避 + 抖动,并设上限;连续失败就降级到本地缓存,而不是把重试队列堆到明天。- 日志里记
X-Request-ID。 报问题时带上它,我们能直接定位到那一次请求。
缓存与新鲜度
- 存下
ETag,回访时带If-None-Match——省带宽也省解析。 - 不要把
/v2/catalog/*的响应交给不理解围栏的共享中间层:它的 body 会随凭据能力位变化,声明就是private, no-store。 - 需要在自己 SQL 里过滤就做 镜像,别在请求路径上硬扛。
- 镜像的本地判定列写成可空且 NULL 放行,冷启动期间不会整站空白。
NSFW 与分级
nsfw=是你自己控制的闸,默认隐藏 r18。要全量就显式传nsfw=true,尤其是在做镜像的时候——不传会在本地留下你察觉不到的空洞。content_rating(事实分级)和content_limit(编辑展示轴)是两个不同的东西,不要混用。- 别把
nsfw=true硬编码进面向终端用户的读路径——那应该跟着用户自己的设置走。
监控
- 给
Deprecation/Sunset响应头设告警。它们出现的那天你还有从容迁移的时间。 - 把
RateLimit-Remaining打进指标,在撞墙之前就能看见趋势。 - 定期 diff
/v2/catalog/openapi.json(免密钥)——加了什么字段、开了什么新端点,一眼就知道。 4xx按code分组统计。突然冒出来的UNKNOWN_INCLUDE通常意味着有人拼错了参数名。
署名
用了这份数据,请按门户首页写明的方式标注来源。这不是法务条款,是对六个上游和所有做整理的编辑的基本尊重。
- 增量镜像目录 — 需要在自己库里过滤时的完整配方。
- AI / MCP 接入 — 让 AI 助手直接调用,不用自己写 HTTP 客户端。