ThinkPHP 6 需手写轻量 CORS 中间件,注册于 app/middleware.php;预检请求返回空 JSON 并设 Access-Control-Allow-Methods;Origin 不可为 * 且带凭证时须指定域名;Nginx 需透传 Origin 头;Swoole 下避免响应头重复写入。

ThinkPHP 6 的 middleware 怎么配 CORS
ThinkPHP 6 默认不开启跨域,得自己加中间件。官方没内置 CORS 中间件,直接用第三方包容易和 Response 处理逻辑冲突,最稳的方式是手写一个轻量中间件。
- 在
app/middleware.php里注册中间件,比如App\Middleware\CorsMiddleware::class - 中间件里只对非预检请求(
OPTIONS)放行响应头,预检请求单独return json([])并设置Access-Control-Allow-Methods - 别把
Access-Control-Allow-Origin写成*同时又带凭证(withCredentials: true),浏览器会直接拒绝——必须指定具体域名,比如https://example.com - 如果用了多级反向代理(Nginx → Swoole),注意
Origin头可能被吞掉,得在 Nginx 配置里显式透传:proxy_set_header Origin $http_origin;
ThinkPHP 5.1 的 header() 方式为什么有时失效
TP5.1 常见做法是在控制器构造函数或 initialize() 里写 header('Access-Control-Allow-Origin: *'),但这个方式在输出已开始后会报错,而且无法覆盖框架底层的 Content-Type 处理逻辑。
- 错误现象:页面空白 + 控制台报
Failed to load resource: net::ERR_INVALID_HTTP_RESPONSE - 根本原因是 ThinkPHP 5.1 的
View或Json输出会提前触发 header 发送,再调header()就无效 - 正确做法是改用
response()->header(),比如:return response($data)->header('Access-Control-Allow-Origin', 'https://a.com'); - 注意
response()->header()必须在返回响应前调用,不能放在echo或dump()后面
跨域时 Cookie 和 Authorization 头拿不到怎么办
不是加了 Access-Control-Allow-Origin 就能带凭证,前后端必须同步配合,漏一环就 401 或 session 失效。
- 后端要明确设置:
Access-Control-Allow-Credentials: true,且Access-Control-Allow-Origin不能为* - 前端发起请求时必须带
credentials: 'include'(fetch)或xhrFields: { withCredentials: true }(jQuery) - ThinkPHP 里 session cookie 默认不支持跨域,需在
config/session.php中设置:'domain' => '.example.com'(注意开头的点),并确保secure和httponly符合当前环境 - 如果用了 JWT,
Authorization头需要额外声明:Access-Control-Allow-Headers: Authorization, Content-Type
Swoole 模式下 CORS 响应头重复出现
在 Swoole 环境中跑 ThinkPHP,常出现响应头被写两次:一次是中间件写的,一次是 Swoole 自动补的,导致浏览器报 Invalid access-control-allow-origin header。
立即学习“PHP免费学习笔记(深入)”;
- 典型表现:响应头里有两行
Access-Control-Allow-Origin,或者Access-Control-Allow-Headers被拼接成乱码 - 原因:Swoole 的
HttpServer默认会自动处理部分 CORS,和你的中间件叠加了 - 解决方法:在
server.php或 Swoole 启动配置中关闭自动 CORS:'enable_static_handler' => false, 'http_compression' => false不相关,关键是检查是否启用了set(['http_parse_post' => true])类似干扰项;更稳妥的是在中间件里用$response->setHeader()替代header(),避免底层重复写入 - 调试技巧:用
curl -I http://your-api.com/xxx查看原始响应头,比浏览器开发者工具更准
跨域真正难的不是加几行 header,而是每个环节都得对齐:Nginx 是否透传、Swoole 是否干预、框架是否提前输出、前端是否配 credentials、cookie domain 是否带点、HTTPS 下 secure 标志是否开启……少一个,请求就静默失败。



















