在本地开发中,我遇到一个比较奇怪的问题:通过 devServer 的 proxy 转发接口请求,理论上浏览器看到的是同源请求,不应该触发跨域限制,但实际情况如下:
- GET 请求:正常返回
- POST 请求 :失败,服务端基于
Origin校验返回错误
问题分析
虽然浏览器同源访问没有跨域限制,但服务端对 Origin 做了安全校验:
- GET 请求 :浏览器通常不携带
Origin头 → 服务端允许 - POST 请求 :浏览器会自动携带
Origin头 → 服务端检查失败 → 报错
换句话说,这不是浏览器跨域机制导致的错误,而是服务端基于 Origin 的安全策略导致的。
解决方案
通过 devServer 的 proxy 修改请求头即可:
javascript
onProxyReq: (proxyReq) => {
proxyReq.setHeader('Origin', 'xxx'); // 修改为服务端允许的 Origin
}
这样浏览器请求仍然是同源,服务端也能通过安全校验,问题解决。
相关知识点梳理
1. 跨域本质
- 浏览器的 同源策略 限制的是 读取响应,不是发送请求
- 也就是说:请求一定可以发出去,但如果不符合跨域策略,浏览器会阻止 JS 访问响应数据
2. 请求分类
- 简单请求 → 直接发 → 再根据响应头决定是否允许 JS 读取
- 复杂请求 → 先发预检 → 检查允许的 Methods/Headers → 再发实际请求
3. CORS 是"放行机制"
- 服务端通过 CORS 响应头告诉浏览器:"可以让前端访问我的资源"
- 核心响应头:
| 头 | 作用 | 注意事项 |
|---|---|---|
Access-Control-Allow-Origin |
指定允许访问的前端源 | 若带凭证,不能是 * |
Access-Control-Allow-Credentials |
是否允许前端携带 cookie | 必须与前端 credentials 配合 |
Access-Control-Expose-Headers |
允许前端访问的自定义响应头 | 默认只能访问安全头 |
Access-Control-Allow-Methods |
预检允许的方法列表 | 复杂请求必需 |
Access-Control-Allow-Headers |
预检允许的自定义请求头 | 复杂请求必需 |
4. devServer proxy 是"绕过机制"
- 核心流程:
- 页面加载: 浏览器 → localhost:3000/home
- 接口请求: 浏览器 → localhost:3000/api/home/list(同源) → devServer(代理转发) → api.xxx.com/home/list
- 浏览器请求 localhost:3000 ✔ 同源 → 不跨域 → 不会触发预检(OPTIONS)
- devServer 转发到后端 ✔ 这是服务器发起的请求(不受同源策略限制) ✔ 浏览器完全感知不到真实后端地址
5. 总结
| 请求类型 | 流程特点 | 浏览器是否检查 CORS | 注意点 |
|---|---|---|---|
| 同源请求 | 浏览器直接发请求 → 返回响应 | ❌ 不检查 | 浏览器不校验 CORS,即使服务端返回 Access-Control-Allow-Origin 为其他源,也能成功。失败通常是服务端逻辑或 Origin 校验导致 |
| 跨域简单请求 | 直接发请求 → 检查响应头 | ✅ 检查 | 浏览器根据 CORS 响应头决定是否允许 JS 读取响应 |
| 跨域复杂请求 | 先发 OPTIONS 预检 → 决定是否发送实际请求 | ✅ 检查 | 预检失败 → 不发送实际请求,浏览器阻止 JS 访问响应 |