因跨域预检踩的坑 —— 预检
最近写的项目部分接口需要跨域,我是这么做的:
- 先创建一个新的 axios 实例,新实例只负责跨域请求。
- 新的实例复用之前实例的拦截器。
- 新实例请求失败,错误信息 CORS。
- 联系后端确认是否开启了跨域,得到肯定答复后,直接用
fetch(url)发现没有CORS错误。
问题分析与结论
- 既然 fetch 可以,基于 XHR 的 axios 会报错,应该是 axios 的配置问题。
- 发现在 axios 复用请求拦截器的时候,请求头里携带了额外的字段。
- 因为携带了额外字段,导致浏览器发请求前会先发一个
preflight预检请求,该请求是options方法,预检后才会尝试发送实际的请求。 - 如果想让预检通过,只是加跨域头是不够的,需要服务端额外处理预检请求。
- 以下代码来自 ChatGPT,我自己跑了一个 demo,尝试处理预检请求。
const express = require('express');
const app = express();
// 处理预检请求的中间件
app.options('*', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.status(200).send();
});
// 处理实际请求的路由
app.get('/api/data', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 处理业务逻辑并发送响应
res.json({ message: 'Hello, world!' });
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});