swoole跨域必须在onrequest中手动处理options预检并设置响应头,因header()无效、需用$response->header(),且access-control-allow-origin不能与credentials共用*。

直接在 onRequest 回调里设响应头 + 拦截 OPTIONS,否则前端永远收不到跨域许可——这不是配置问题,是漏处理预检请求。
为什么 header() 在 Swoole 里完全无效
Swoole 的 HTTP 服务器不走 PHP 的 SAPI 流程,header() 函数根本不会被识别,也不会写入响应头。所有响应控制必须通过 $response->header() 或直接操作 $response 对象完成。
- 你在
workerStart、start或控制器里调header(),全都不生效 - 即使写了
ob_start()也没用,Swoole 不接管输出缓冲 - 错误现象:控制台报
No 'Access-Control-Allow-Origin' header is present,但后端日志里看似“执行了”
必须手动处理 OPTIONS 预检请求
浏览器在发真实请求(如 POST 带 Authorization)前,一定会先发一次 OPTIONS 请求。Swoole 不会自动响应它,你得显式判断并返回 204 状态码和 CORS 头。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 不拦截
OPTIONS→ 返回 405 Method Not Allowed 或静默超时 - 只加头不返回 → 前端卡在预检阶段,后续请求根本不会发出
- 正确做法:
if ($request->getMethod() === 'OPTIONS') { $response->status(204)->end(); return; } - 注意:204 响应体必须为空,不能
end('')或end('{}'),否则某些客户端会解析失败
Access-Control-Allow-Origin 不能写 * 时怎么办
只要前端用了 credentials: 'include'(比如带 Cookie 或 Authorization),后端就绝对不能设 Access-Control-Allow-Origin: *,浏览器会直接丢弃整个响应——连控制台都不会报 CORS 错,只会显示 Failed to fetch。
- 必须从请求头读
Origin,再白名单校验:$origin = $request->header('origin'); - 白名单数组建议硬编码或从配置加载,避免正则或模糊匹配引入安全风险
- 匹配成功才写头:
$response->header('Access-Control-Allow-Origin', $origin); - 务必加
$response->header('Vary', 'Origin');,否则 CDN 或代理可能缓存错响应 - 如果没匹配上,别返回 204,应返回 403,避免暴露接口存在性
响应头重复写入导致 500 或空白页
多个中间件、框架层(如 Hyperf/EasySwoole)、或你自己写的逻辑都可能往同一个 $response 写头,Swoole 会直接报错或忽略后续写入。
- 检查是否在
onRequest里多次调$response->header()同一个 key - 避免在业务逻辑里再补 CORS 头,统一收口到最外层逻辑
- 如果用了框架,优先用其 CORS 中间件(如 Hyperf 的
CorsMiddleware),别自己手写两套 - 调试技巧:在
onRequest结尾加var_dump($response->getHeaders());(仅开发环境),确认头是否已存在
真正容易被忽略的点是:预检响应必须严格满足浏览器要求——状态码、空响应体、精确的头字段名大小写、Vary 头缺失导致的缓存污染。这些细节出错,前端不会给你明确提示,只会“看起来像没跨域”。










