hyperf中corsmiddleware失效主因是options预检请求被路由层拦截返回405,未进入中间件;需全局注册中间件、启用auto_options、校验origin白名单,并从context获取response对象。

Hyperf里加了CorsMiddleware却没生效,基本不是头写错了,而是中间件压根没执行——尤其是OPTIONS预检请求被路由层拦截后直接返回405,连中间件的边都没摸到。
OPTIONS请求卡在路由层,返回405而不是进中间件
Hyperf默认不自动注册OPTIONS路由。浏览器发来预检请求时,如果当前路径没定义OPTIONS方法,hyperf/routing会抛出MethodNotAllowedHttpException,响应405,整个中间件链就此中断。
- 检查日志里有没有
MethodNotAllowedHttpException或405 Method Not Allowed - 确认你访问的路径(比如
/api/user)是否在路由中显式声明过OPTIONS,哪怕只写Router::addRoute('OPTIONS', '/api/user', ...) - Hyperf 3.1+ 可启用
auto_options:在config/autoload/routes.php里设'auto_options' => true,它会自动为所有已注册的GET/POST/PUT等路径补上OPTIONS
中间件没挂对位置,只对部分路由起作用
CorsMiddleware如果只通过@Middleware注解或middleware数组配给某个Router::addGroup,那未覆盖的路径(尤其是根路径/、健康检查/ping等)照样掉进405陷阱。
- 必须把中间件注册到全局:在
config/autoload/middlewares.php的'http'数组顶层添加,例如:App\Middleware\CorsMiddleware::class - 别写成
['http' => ['App\Middleware\CorsMiddleware']]这种嵌套错误格式,应是'http' => [App\Middleware\CorsMiddleware::class] - 若同时用了鉴权中间件(如
AuthMiddleware),CorsMiddleware必须放在它前面——否则预检请求先被鉴权拦住,根本走不到CORS逻辑
Response对象用错实例,Header写不进真实响应
很多示例直接new \Hyperf\HttpMessage\Server\Response(),这会创建一个脱离上下文的新对象,后续withHeader()操作全白费,Header不会出现在最终HTTP响应里。
- 必须从上下文取当前响应:
$response = Context::get(ResponseInterface::class) - 所有头操作要链式调用后,再写回上下文:
Context::set(ResponseInterface::class, $response->withHeader(...)) - 处理
OPTIONS分支时,除了withStatus(204),还必须withBody(new SwooleStream('')),否则Swoole协程可能卡住连接 - 生产环境禁用
Access-Control-Allow-Origin: *+Access-Control-Allow-Credentials: true组合,浏览器明确拒绝——得根据Origin头动态匹配白名单并回写具体域名
最常被忽略的是auto_options开关和Context::get(ResponseInterface::class)这两处;一旦漏掉,无论头写得多规范,都只是在往空气里塞Header。










