API废弃需用RFC标准Deprecated响应头配410/406状态码,禁止404或空响应;版本解析须统一函数处理路径/头/查询参数;废弃路由不可删除,须拦截返回410并记录日志。

API 版本废弃必须用 Deprecated 响应头 + 状态码 410 或 406
用户调用已下线接口时,不能只返回 404 或空 JSON,否则客户端无法区分“路径错误”和“版本淘汰”。PHP 中需显式设置 Deprecated 响应头,并配合语义化状态码:
-
HTTP/1.1 410 Gone:该版本彻底不可用(如/v1/users已删除),后续请求永远失败 -
HTTP/1.1 406 Not Acceptable:客户端Accept头声明了已废弃的媒体类型(如application/vnd.myapi.v1+json) - 务必在响应头中写入:
header('Deprecated: Fri, 01 Jan 2025 00:00:00 GMT');(格式必须为 RFC 7231 定义的 HTTP-date) - 不要用
X-Deprecated这类自定义头——标准客户端(如 Axios、OkHttp)不识别,OpenAPI 工具链也不解析
兼容性路由分发不能靠 strpos() 或正则硬匹配 /v\d+/
简单字符串匹配会导致 /v123/users 误判为 v1,或 /v2alpha/orders 漏匹配。真实场景中,版本标识可能出现在路径、查询参数、请求头或媒体类型中:
- 路径段版本(推荐):
/api/v2/users→ 用preg_match('@^/api/(?<version>v\d+(?:\.\d+)?)@', $path, $m)</version>提取,注意v2.1要支持小数点 - Accept 头版本:
Accept: application/json; version=2→ 解析$_SERVER['HTTP_ACCEPT'],别直接explode(';', ...),要按 RFC 7231 分割参数 - Query 版本(仅过渡期):
?version=v2→ 必须校验是否被显式传入,且优先级低于路径和头,避免被恶意构造绕过 - 所有版本提取逻辑必须统一走一个
resolveApiVersion()函数,禁止在 controller 里重复写匹配逻辑
Accept 头解析失败时默认回退到最新稳定版,但必须记录告警日志
当客户端发送 Accept: application/vnd.myapi+json(无版本)或格式非法时,不能直接报错 406,而应启用兼容策略:
- 默认使用当前 latest stable 版本(如 v3),但响应头中必须添加:
Warning: 299 - "Fell back to v3 due to missing/invalid version in Accept" - 日志中记录完整原始
Accept值、客户端 IP、User-Agent 和时间戳,方便后续分析迁移进度 - 禁止静默降级——没 Warning 头、没日志,等于放弃可观测性,运维和 SDK 团队无法判断哪些客户端还没升级
- 如果业务要求强版本约束(如金融类 API),则改用
400 Bad Request并返回明确错误字段:{"error": "version_required", "in": "Accept"}
废弃接口的 PHP 路由注册不能删,但必须拦截并拒绝执行业务逻辑
直接从 routes.php 或框架路由表里删掉 /v1/* 规则,会导致 404,掩盖真实意图。正确做法是保留路由,但在中间件或控制器入口拦截:
立即学习“PHP免费学习笔记(深入)”;
- Laravel 示例:在
EnsureApiVersionActive中间件里检查$request->route()->getActionName()是否属于已废弃控制器方法,是则立即abort(410) - 原生 PHP:在路由分发前插入判断,如
if (isDeprecatedVersion($version)) { http_response_code(410); exit(json_encode(['message' => 'API version deprecated'])); } - 关键点:废弃路由仍需参与路由匹配,否则无法统计调用量、无法生成 OpenAPI deprecation 标记、也无法做灰度下线(比如只对 5% 流量返回 410)
- 不要在废弃控制器里留空方法或
return [];—— 这会让监控系统误判为成功调用
实际落地中最容易被忽略的是 Deprecated 响应头的时间格式校验和 Warning 头的标准化写法。RFC 7234 明确要求 Warning 的 warn-code 必须是三位数字,且 warn-agent 字段不能省略;而 Deprecated 头若写成 'Deprecated: 2025-01-01' 会被大多数 HTTP 客户端忽略——必须转成格林威治时间的完整日期字符串。



















