核心原因是浏览器预检(OPTIONS)被忽略、响应头缺失或冲突、JSON输出不规范;必须在中间件中拦截OPTIONS请求返回204,成套设置Access-Control-Allow-Origin(带凭据时不可为*)、Methods、Headers,并用json()方法规范输出JSON。

ThinkPHP前后端分离时跨域请求失败,核心原因通常是浏览器预检(OPTIONS)被忽略、响应头缺失或冲突、JSON输出不规范这三类问题。单独加 Access-Control-Allow-Origin: * 往往不够,尤其在带凭证、自定义 header 或非简单请求时会直接卡住。
必须响应 OPTIONS 预检请求
前端若设置 Content-Type: application/json、Authorization header,或使用 PUT/DELETE 方法,浏览器会先发一次 OPTIONS 请求。ThinkPHP 默认不处理它,返回 404 或 500,整个请求就中断了。
- 在中间件中判断:
if ($request->isOptions()) { return response('', 204); } - 确保响应状态码是 204(无内容)或 200,不能是 404/500
- 204 响应体为空,但必须带上完整的 CORS 头:Allow-Origin、Allow-Methods、Allow-Headers
响应头要成套且匹配场景
CORS 头不是只写一个就行,必须按需组合,尤其注意凭据(credentials)和通配符 * 的互斥关系:
- 允许携带 Cookie 或 Authorization:设
Access-Control-Allow-Credentials: true,此时Access-Control-Allow-Origin必须是具体域名(如https://your-vue-app.com),不能用* - 允许的请求方法要写全:
GET, POST, PUT, DELETE, OPTIONS - 前端用的 header(比如
X-Requested-With、Authorization、Content-Type)必须列在Access-Control-Allow-Headers中
JSON 输出必须语义正确
即使 CORS 头全了,如果后端返回的不是标准 JSON 响应,前端 fetch 仍会报 TypeError: Failed to fetch 或解析失败:
立即学习“PHP免费学习笔记(深入)”;
- 必须设置
Content-Type: application/json; charset=utf-8,不能是text/html或漏掉charset - 优先用框架原生方式返回:
return json($data);或return response()->json($data);,避免手动echo json_encode()后 header 被覆盖 - 检查 JSON 是否合法:用
json_last_error()判定,防止数组含资源句柄、循环引用或中文乱码 - 禁止在 JSON 前后输出任何空格、BOM、调试信息(如
var_dump)
验证码等依赖 Session 的功能会失效
跨域下浏览器默认不发送 Cookie,导致 ThinkPHP 的 Session ID 无法传递,验证码校验、登录态维持全部失效:
- 放弃基于 Session 的验证码绑定,改用服务端生成唯一
captcha_id,存入 Redis 并返回给前端 - 前端提交时把
captcha_id和用户输入一起发到校验接口,后端查 Redis 比对 - 登录态建议改用 JWT 或 token + Redis 存储,通过 Authorization header 传递



















