跨域,一个说腻了的话题,今天遇到一个新的情况,单独拎出来说说;
情景再现
b.site有一个ajax请求a.site的某一个地址,post请求+自定义header(假设,header头为X-Application-Token
),ok,妥妥的跨域,那么自然加上以下代码(以express.js为例):
app.options('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "X-Application-Token")
// call the path service
})
app.post('/a-cors-request-path', (req, res) => {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "X-Application-Token")
// call the path service
})
反复确认了相关配置已经设置好,但浏览器仍报错:
Access to XMLHttpRequest at 'a.site' from origin 'b.site' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
排查
- 返回说"not have HTTP ok status"
那么说明option请求没有返回200,打开postman发送请求尝试看看,成功返回...
- 自己启动一个Express Server,尝试复现
已经能够确认,option不通过和状态码有关,那么为什么浏览器内非200,而postman发送option请求正常返回200 ?
打印headers,一口老血...
结论
除了常见的跨域问题,也要考虑实现时的业务逻辑,比如本情境下,错误的在option中也调用相关服务验证了X-Application-Token
,而option请求在浏览器内是不会携带额外的header信息的,这才导致了浏览器内 not HTTP ok status,而postman正常的原因.
额外
后来利用老的Microsoft Edge浏览器(Edge legacy)调试,发现会清楚的返回400 Bad Request,所以如果option请求能够返回精确的HTTP code,也会更利于开发人员排查问题,后续修改后完美解决.