API必须带版本号上线,路由需绑定版本与环境前缀,物理隔离开发/测试/生产路径,禁用手动解析版本,校验须前置且返回标准JSON错误响应,废弃接口需Nginx层拦截并全链路追踪。

API不带版本号直接上线,等于给后续迭代埋雷——PHP里90%的“兼容性故障”都源于此。
路由必须绑定版本号和环境前缀
PHP框架层或Web服务器层漏掉版本前缀,会导致v1接口被v2请求误打、测试参数污染生产数据。Laravel必须用Route::prefix('api/v1'),Slim必须用$app->group('/api/v1', ...);更稳妥的是在Nginx配置里统一加location /api/v1/,避免框架路由漏配。
开发、测试、生产三套路径要物理隔离:/dev-api/v1/、/test-api/v1/、/api/v1/。CI流程只需改一个Nginx变量,不用动任何PHP代码。
- 禁用
$_GET['version']或$_POST['v']手动解析——攻击者可伪造、审计难追溯 - 版本号只用
v1、v2,不用v1.2.0或2024-05——PHP路由正则匹配慢,且语义化版本对HTTP路径无实际意义 - 旧版本下线前,必须配置Nginx级
return 301跳转,并返回X-Deprecated-Warning响应头
参数校验必须在业务逻辑之前完成
把if (empty($_POST['email']))写在Controller里,等于放弃错误响应一致性。校验失败时,应立刻返回标准JSON结构,状态码严格为400或422,Content-Type必须是application/json。
立即学习“PHP免费学习笔记(深入)”;
- 用Laravel的
validate()、Symfony Validator或自建RequestValidator类,在Middleware或__construct()中执行 - 必填字段用
required,非空字符串用required|string|min:1,别写trim($_POST['name']) === '' - 敏感字段如
password在校验层就unset(),不让它进入后续流程 -
filter_var($email, FILTER_VALIDATE_EMAIL)不能单独用——它不校验长度、不支持中文邮箱,建议加strlen($email) + 自定义正则
测试必须覆盖非200状态码路径
PHPUnit只断言$response->assertJson([]),等于没测。真实线上故障80%发生在权限、限流、参数错误场景,不是“功能通不通”,而是“错的时候返得对不对”。
- 显式断言
$this->json('POST', '/api/v1/login', ['email' => ''])后跟$response->assertStatus(422) - 必须覆盖
401(未登录)、403(权限不足)、429(限流)——特别是429,Redis限流常见错误是每次请求都INCR再EXPIRE,导致窗口重置失效 - 用Postman或
curl -I人工验证响应头:确认X-RateLimit-Limit、X-Deprecated-Warning等头存在且值正确
废弃接口不能只删代码
删掉routes/web.php里的某条路由,不代表API已下线。客户端缓存、第三方系统调用、监控埋点可能还在引用它。真正的废弃,是“可观测+可追溯+可拦截”的闭环。
- Nginx层保留该路径,返回
410 Gone并附带X-API-Deprecated: true头 - 所有对该路径的请求,必须记录到独立日志文件(如
/var/log/php/deprecated.log),含IP、UA、时间戳 - 数据库里维护
api_deprecation_log表,记录每次调用来源系统ID,用于通知下游方迁移 - 若该接口曾被OAuth2 scopes授权,需同步从
oauth_scopes表中移除对应项,防止权限残留
最易被忽略的一点:废弃不只是删代码,而是让每一次非法调用都留下痕迹、产生反馈、推动收敛——否则“已下线”的接口,半年后还会在错误日志里反复出现。



















