Express cors 中间件和自定义中间件函数设置 Header 的区别
本文最后更新于:2025年1月29日 凌晨
今天又踩了个大坑,问题是这样的。
我正在使用 GraphQL
的 SANDBOX 环境测试接口,需要 Express
配置跨域。origin 的值是 https://studio.apollographql.com
, 本来是一件很简单的事情,但是我又折腾了一个下午。
一开始沙盒环境请求 http://localhost:8080/graphql
报错,
1 |
|
我心想这简单,配置一下 Access-Control-Allow-Origin
设置为 *
即可。但是呢,因为后续需要模拟登录状态,保存 Cookie, 需要设置 Access-Control-Allow-Credentials
为 true
, 那么 Access-Control-Allow-Origin
就不能为 *
通配符了。所以 Access-Control-Allow-Origin
需要设置为具体的值 https://studio.apollographql.com
,形成一个类似于白名单的效果。
最终的设置:
1 |
|
但是 GraphQL
的沙盒环境还是一直报错,405 Method Not Allowed
, 即使设置了 Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
也不行,预检请求响应字段里面还有一个 ALLOW: "GET, POST"
, 看了一下 MDN 文档,发现是 405 的响应必须要一个 ALLOW 字段,显示当前 server 支持的请求方法列表。
我的疑惑来了,我明明配置了跨域的请求方法,为什么还会报错?
想了好久。
用 cors
中间件设置跨域的参数:
1 |
|
居然就不报错了,奇怪啊。去翻看了一下 cors
的源代码,不长,就两百多行。
我发现除了一些基础的配置之外, cors
做了一个判断,当请求的方法是 OPTIONS
的时候,直接 res.end()
结束了响应,而其他情况,则调用 next()
, 继续往下运行。
到这个时候,我明白了。
OPTIONS 预检请求,是询问 server 是否当前 origin 可以访问,一般来讲,预检请求成功返回,就是代表 origin 可以做请求了(由浏览器控制)。这个时候,server 再定义一些字段来精细化控制后续的请求。
我遇到的情况报错是因为, 针对预检请求,没有做特殊处理,导致后续的 Apollo Server
对这个 OPTIONS
请求报错了,导致预检请求失败。前面所做的配置,也就无效了。
所以说, 自定义预检请求的中间件函数应该这样写:
1 |
|
针对预检请求,设置完参数后,直接返回,不要让后续的中间件再进行处理了。
弄清楚问题后,我直接注释了我写的配置,直接使用用 cors
中间件配置, 一了百了。