thinkphp 5.1+ 必须用中间件显式拦截 options 请求并返回 204 状态码空响应,因框架默认不识别 options 导致 404/405;响应头须通过 $response->header() 设置,且中间件需注册在 middleware.php 首位以确保 cors 头优先注入。

ThinkPHP 5.1+ 必须用中间件处理跨域,且必须显式拦截 OPTIONS 请求并返回 204;直接在控制器或入口文件写 header() 极易被框架后续逻辑覆盖,导致预检失败。
为什么 TP5 中间件必须手动处理 OPTIONS 请求
浏览器对非简单请求(如带 Authorization、Content-Type: application/json 或自定义 header 的请求)会先发一次 OPTIONS 预检。TP5 默认不识别该请求为合法 HTTP 方法,若中间件未主动拦截,框架会走完整路由匹配 → 找不到对应路由 → 返回 404 或 405,前端卡死无报错。
- 不加
if ($request->isOptions()) { return response('', 204); },哪怕设置了所有 CORS 头,预检也通不过 - 返回 204 状态码是 W3C 规范要求,不能用 200 替代
- 返回内容必须为空字符串,不能带 body(否则部分浏览器拒绝解析)
中间件里设置响应头要用 $response->header(),别用 header()
TP5 的响应对象是统一出口,header() 是 PHP 原生函数,它直接写入 SAPI 输出缓冲,而框架后续可能调用 Response::send() 重置或覆盖这些头 —— 尤其在开启调试模式或使用某些扩展时更明显。
- 正确写法:
$response->header('Access-Control-Allow-Origin', '*') - 错误写法:
header('Access-Control-Allow-Origin: *')(看似生效,上线后常失效) - 若需动态白名单,必须从
$request->header('origin')取值比对,再决定是否写入该 origin,不能硬编码*后又设Access-Control-Allow-Credentials: true,否则浏览器直接拒收
注册中间件要放在 middleware.php 全局数组首位
TP5 中间件执行顺序即注册顺序,CORS 头必须在响应生成前注入。如果把它放在鉴权、日志等中间件之后,那些中间件可能已修改或锁定响应头。
- 检查
app/middleware.php是否类似这样:return [ \app\middleware\Cors::class, \app\middleware\Auth::class, // ... ]; - 路径必须是完整命名空间,比如
\app\middleware\Cors::class,不是Cors::class或相对路径 - 类文件位置应为
app/middleware/Cors.php,命名空间需匹配:namespace app\middleware;
携带 Cookie 时 Access-Control-Allow-Origin 不能为 *
只要前端 AJAX 设置了 withCredentials: true,服务端就必须把 Access-Control-Allow-Origin 设为具体域名(如 https://admin.example.com),且必须和请求头中的 Origin 完全一致 —— 协议、域名、端口缺一不可。
- 否则浏览器静默丢弃响应,控制台只显示 “CORS header ‘Access-Control-Allow-Origin’ does not match ‘xxx’”
- 建议在中间件中做白名单校验:
$origin = $request->header('origin'); $allowed = ['https://admin.example.com', 'http://localhost:3000']; if ($origin && in_array($origin, $allowed)) { $response->header('Access-Control-Allow-Origin', $origin); $response->header('Access-Control-Allow-Credentials', 'true'); } - 注意:Nginx/Apache 层配置的 CORS 头在此场景下无效,因为它们无法动态读取请求头中的
Origin
真正麻烦的从来不是加几行头,而是 OPTIONS 请求没被接住、凭证模式下 Origin 没做校验、或者中间件注册顺序错位 —— 这三处出问题,90% 的跨域故障就卡住了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











