Webman跨域失败主因是OPTIONS预检请求未被路由匹配,导致CORS头无法发出;需用Route::any()或显式处理OPTIONS,精确设置Access-Control-Allow-Origin并禁用Nginx头覆盖。

Webman 的跨域问题,本质不是“加不加头”,而是“头有没有发出去”——尤其当用 Route::post() 这类限定方法路由时,浏览器的 OPTIONS 预检请求根本进不到你的中间件或控制器里,直接 404 或被拒。
为什么 Route::post() 会导致跨域失败
浏览器对非简单请求(如带 Content-Type: application/json、Authorization 头,或用 PUT/DELETE 方法)会先发一个 OPTIONS 请求做预检。这个请求的 HTTP 方法是 OPTIONS,但你的路由只注册了 POST,所以 Webman 根本不匹配该路由,中间件不会执行,CORS 响应头自然不会发出。
-
Route::post('/api/login', [...])→ 只响应POST,OPTIONS被忽略 → 浏览器收不到Access-Control-Allow-Origin→ 报错 “No ‘Access-Control-Allow-Origin’ header is present” -
Route::any('/api/login', [...])→ 匹配所有方法,OPTIONS进来后中间件可拦截并返回正确头 → 预检通过 - 即使你写了中间件,它也只在路由匹配成功后才运行;路由不匹配,中间件就是摆设
Access-Control-Allow-Origin 不能写 * 时怎么处理凭证
前端若设置了 credentials: 'include'(比如要传 Cookie),服务端必须同时满足两个条件:1)Access-Control-Allow-Origin 不能是 *;2)必须精确匹配 Origin 域名。否则浏览器直接拒绝响应。
- 先从
$_SERVER['HTTP_ORIGIN']取值,再比对白名单数组(如['https://admin.example.com', 'http://localhost:3000']) - 匹配成功才输出
header("Access-Control-Allow-Origin: $origin"),不匹配就别发这行头(否则可能被绕过) -
Access-Control-Allow-Credentials: true必须和具体 Origin 同时存在,二者缺一不可 - 注意:Nginx 反向代理时,
Origin头可能被过滤,需确认proxy_set_header Origin $http_origin;已配置
中间件里处理 OPTIONS 请求的正确姿势
Webman 中间件必须显式响应 OPTIONS,且不能让它继续往下走——否则可能触发后续逻辑(如数据库查询、鉴权失败等),既浪费资源又暴露行为。
立即学习“PHP免费学习笔记(深入)”;
- 在中间件
handle()方法开头判断:if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { return $next($request); }是错的,因为$next仍会进控制器 - 正确做法是立即返回响应:
return response('', 204)->withHeaders([...]); - 响应状态码建议用
204 No Content(语义最准),不要用200+ 空 body - 必须包含完整 CORS 头:
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers,缺一不可
Nginx 层面可能覆盖 PHP 头的坑
如果你用宝塔或自建 Nginx 反代 Webman,Nginx 默认会清除或重写某些响应头——尤其是 Access-Control-Allow-Origin 这类非标准头,导致 PHP 设置的头完全失效。
- 检查 Nginx 配置中是否有
add_header指令覆盖了 PHP 的头(例如重复设置Access-Control-Allow-Origin) - 确保 Nginx 的
location块里有:add_header Access-Control-Allow-Origin $http_origin always;(always关键字才能让非 2xx 响应也生效) - 禁用
fastcgi_hide_header或类似指令,避免它把 PHP 的header()结果吃掉 - 最稳妥方式:关掉 Nginx 的 CORS 相关配置,全部交给 Webman 中间件控制,避免双层头冲突
真正卡住人的从来不是“怎么加头”,而是 OPTIONS 请求是否被路由捕获、是否被中间件及时终结、以及 Nginx 是否在背后悄悄抹掉了你写的头——这三个环节漏掉任何一个,CORS 就会静默失败。



















