返回文章列表

因跨域预检踩的坑 —— 预检

最近写的项目部分接口需要跨域,我是这么做的:

  1. 先创建一个新的 axios 实例,新实例只负责跨域请求。
  2. 新的实例复用之前实例的拦截器。
  3. 新实例请求失败,错误信息 CORS。
  4. 联系后端确认是否开启了跨域,得到肯定答复后,直接用 fetch(url) 发现没有 CORS 错误。

问题分析与结论

  1. 既然 fetch 可以,基于 XHR 的 axios 会报错,应该是 axios 的配置问题。
  2. 发现在 axios 复用请求拦截器的时候,请求头里携带了额外的字段。
  3. 因为携带了额外字段,导致浏览器发请求前会先发一个 preflight 预检请求,该请求是 options 方法,预检后才会尝试发送实际的请求。
  4. 如果想让预检通过,只是加跨域头是不够的,需要服务端额外处理预检请求。
  5. 以下代码来自 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');
});