预检请求(options)被拦截本质是服务端未响应或响应不合规;需在中间件开头判断$request->isoptions()并返回204,同时完整设置access-control-allow-*头,且中间件须注册靠前、位置正确。

预检请求(OPTIONS)被拦截,本质是服务端没响应或响应不合规。浏览器在发复杂请求前会先试探,如果这一步卡住,后续请求根本不会发出。
确认是否触发了预检
不是所有请求都会触发预检。只有满足以下任一条件时,浏览器才会先发 OPTIONS:
- 使用了非简单方法(如 PUT、DELETE、PATCH)
- 设置了自定义请求头(如 Authorization、X-Request-ID)
- Content-Type 不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain
用浏览器开发者工具的 Network 标签页查看,如果看到一个状态码为 404、405 或 500 的 OPTIONS 请求,说明预检没被正确处理。
中间件必须拦截并返回 204 或 200
ThinkPHP 不会自动响应 OPTIONS 请求,必须由中间件主动终止流程,不能让它继续走到控制器。常见错误是只设 header 却没 return 响应。
- 在中间件 handle 方法开头判断:if ($request->isOptions()) { return response('', 204); }
- 不要用 exit() 或 die(),ThinkPHP 的响应生命周期需要统一管理
- 返回 204 最规范(无响应体),200 也可接受,但 body 必须为空
响应头必须完整且匹配前端行为
预检响应里缺任何一个关键头,浏览器都会拒绝后续请求:
- Access-Control-Allow-Methods:列出前端实际用到的方法,比如 'GET, POST, PUT, OPTIONS'
- Access-Control-Allow-Headers:必须包含前端发送的所有自定义头,比如 'Authorization, Content-Type, X-Token'
- Access-Control-Allow-Origin:若前端带 credentials,这里不能写 *,要精确匹配 origin 头的值
- Access-Control-Allow-Credentials:只要前端 fetch 中有 credentials: 'include',后端就必须设为 true,且 Origin 不能为 *
检查中间件注册和执行顺序
中间件没生效,等于没写。确保:
- 中间件类已正确添加到 app/middleware.php 全局中间件列表中
- 位置靠前(建议放在第一个),避免被后续中间件覆盖 header
- 没在路由分组里漏配 middleware,特别是 API 路由用了独立分组时
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











