swoole 不自动处理 options 请求,需在 onrequest 回调中手动拦截并返回 204 状态码及必要 cors 头,否则会导致跨域预检失败;onworkerstart 等回调无法替代 onrequest 处理逻辑。

为什么 Swoole 的 OPTIONS 请求没被自动处理
Swoole 默认不会拦截或响应 OPTIONS 请求,它原样透传给你的 PHP 回调(比如 onRequest)。如果你没在逻辑里显式判断 $request->server['request_method'] === 'OPTIONS',这个请求就可能 404、超时,或者被下游中间件反复重试——尤其在跨域预检场景下特别明显。
在 onRequest 中手动返回 204 是最稳的做法
别依赖框架或中间件自动处理,直接在 onRequest 回调里拦截并短路返回。重点不是“怎么返回”,而是“什么时候返回”和“返回什么”:
-
OPTIONS请求通常无 body,返回204 No Content最符合语义,比200 OK更安全(避免某些客户端解析空 body 出错) - 必须设置
Access-Control-Allow-Methods、Access-Control-Allow-Headers等头,否则浏览器仍会拒绝后续真实请求 - 如果只对特定路径放行(比如
/api/),记得先做strpos($request->server['request_uri'], '/api/') === 0判断,别全局放行
if ($request->server['request_method'] === 'OPTIONS') {
$response->status(204);
$response->header('Access-Control-Allow-Origin', '*');
$response->header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
$response->header('Access-Control-Allow-Headers', 'Content-Type,Authorization,X-Requested-With');
$response->end();
return;
}
用 Swoole\Http\Server 的 onWorkerStart 做预热会踩坑
有人想在 onWorkerStart 里提前注册路由规则或挂载中间件来统一处理 OPTIONS,这不可行。Swoole 的 HTTP 服务器不支持运行时动态路由匹配,所有请求都只会进 onRequest,没有“路由层”可 hook。强行在 worker 启动时初始化一堆闭包或反射类,反而增加启动延迟,且无法按请求路径差异化控制。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 不要试图用
$_SERVER或全局变量模拟“中间件链”来处理OPTIONS - 不要在
onRequest外的任何回调里尝试调用$response->end()—— 此时$response实例根本不存在 - 如果你用的是 Hyperf/Slim/Swoft 等框架,确认它们是否已内置 CORS 中间件;若启用了,优先关掉它再手写,避免 header 冲突
curl 测试时注意 -X OPTIONS 和 -I 的组合
本地验证容易漏掉关键点:用 curl -X OPTIONS -I http://127.0.0.1:9501/api/test 检查状态码和 header,而不是只看 curl -X OPTIONS 的 body 输出(因为 204 没 body)。如果返回 405,说明你没拦住请求,还在走默认逻辑;如果返回 200 但缺 Access-Control-Allow-Origin,说明 header 设置位置错了(比如写在了 $response->end() 之后)。
真实环境里,浏览器发的预检请求还带 Access-Control-Request-Method,虽然你不用读它,但得确保你的 Allow-Methods 包含它所声明的方法,否则预检失败。










