thinkphp跨域失败主因是cors中间件未正确注册或顺序错误、options预检未处理、access-control-allow-headers/credentials配置冲突;需手动注册think\middleware\cors::class并置前,显式列出headers,origin不能用*配credentials。

ThinkPHP跨域失败,90%不是没配,而是配错了位置、配错了参数、或者被其他逻辑覆盖了头。
中间件没注册或顺序错,Cors 根本没跑
ThinkPHP 6/8 自带 think\middleware\Cors,但它默认不启用。你得手动加进 app/middleware.php 的全局中间件数组里:
- 必须写成
think\middleware\Cors::class,不能写字符串'cors'(除非你额外绑定了别名) - 推荐放在数组靠前位置(比如第2或第3位),确保它在 Session、JWT 验证等中间件之前执行、之后结束
- 如果用了路由分组限定跨域,要在
route/app.php里显式绑定:->middleware(\think\middleware\Cors::class),不能只写->middleware('cors') - 检查有没有其他中间件(比如自定义 header 设置)重复写
Access-Control-Allow-Origin—— 多次设置会触发浏览器报错CORS header ‘Access-Control-Allow-Origin’ cannot be used with wildcard
OPTIONS 预检请求 404 或 500,说明没被正确拦截
前端发了 Content-Type: application/json 或带 X-Auth-Token 这类非简单 header,浏览器会先发 OPTIONS 请求。ThinkPHP 默认不响应它,导致卡死。
- 官方
Cors中间件会自动处理OPTIONS并返回204,但前提是它真被执行了 —— 所以先确认上一步的注册和顺序 - 如果用的是自定义中间件,必须显式判断:
if ($request->isOptions()) { return response('', 204); } - 别依赖
Route::options()单独补路由,它容易漏(尤其资源路由、闭包路由下),中间件方式更稳 - Nginx 等 Web 服务器可能直接拦截
OPTIONS,不进框架 —— 开启AppDebug模式看日志,确认请求是否抵达 PHP 层
Access-Control-Allow-Headers 被忽略,实际是通配符 * 在作祟
前端发了 X-Auth-Token,后端配了 'allowHeaders' => ['*'],但浏览器仍报错 Request header field x-auth-token is not allowed。
- 只要
supports_credentials => true(或withCredentials => true),Access-Control-Allow-Headers就不允许用*,必须明确列出所有前端会发的 header - 大小写要严格匹配:前端发
X-Auth-Token,你就得写'X-Auth-Token',不能写成'x-auth-token'(部分环境校验敏感) - 常见要列全的有:
'Content-Type'、'Authorization'、'X-Requested-With'、'X-Auth-Token'、'Accept' - TP8 的
topthink/think-cors包里config/cors.php的allowed_headers也得避开['*'],改用具体数组
Access-Control-Allow-Origin 设成 * 却带 cookie,浏览器直接拒收
前端 fetch 加了 credentials: 'include',后端却配了 Access-Control-Allow-Origin: '*',控制台立刻报错 The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*' when the request's credentials mode is 'include'。
- 只要涉及 cookie、Authorization header 或
XMLHttpRequest.withCredentials = true,Access-Control-Allow-Origin就必须写死域名,比如'https://localhost:5173'或'https://your-site.com' - 多域名支持要用数组白名单:
['https://a.com', 'https://b.com'],注意协议、端口、末尾斜杠都要完全一致 - 别在中间件里用
header()函数硬塞头 —— TP6+ 基于 PSR-7,应操作$response->header()或$response->withHeader() - 最隐蔽的坑:某些中间件(如 JWT 验证)在异常时提前
return json()或exit,导致跨域中间件根本没机会写头 —— 检查所有return和exit是否打断了中间件链
真正卡住的地方,从来不是“要不要开跨域”,而是“谁在写头、谁在删头、谁在拦 OPTIONS”。盯住中间件执行顺序、响应对象生命周期、以及预检请求的实际走向,比反复调 header() 有用得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











