前端跨域请求解决方案
理解跨域原理,掌握 CORS、Nginx 代理、Node 中间件等常用跨域方案
问题
前端如何实现跨域请求?
解答
什么是跨域
同源策略要求”协议+域名+端口”三者相同,任意一个不同都算跨域。跨域请求能发出去,服务端也能正常返回结果,但响应会被浏览器拦截。
允许跨域加载资源的标签:<img>、<link>、<script>
CORS
CORS 是最常用的跨域方案,关键在于服务器配置。分为简单请求和非简单请求。
简单请求
同时满足以下条件:
- 请求方法是 HEAD、GET、POST 之一
- 请求头不超过 Accept、Accept-Language、Content-Language、Content-Type(仅限 application/x-www-form-urlencoded、multipart/form-data、text/plain)
服务器响应头示例:
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
非简单请求
PUT、DELETE 请求或 Content-Type 为 application/json 时,浏览器会先发送 OPTIONS 预检请求。
减少 OPTIONS 请求次数的方法:
Access-Control-Max-Age: 86400
携带 Cookie
需要同时满足:
- 服务器设置
Access-Control-Allow-Credentials: true - 客户端设置
xhr.withCredentials = true Access-Control-Allow-Origin不能为*,必须指定明确域名
Nginx 代理
配置代理服务器转发请求:
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://domain2.com:8080;
proxy_cookie_domain www.domain1.com www.domain2.com;
add_header Access-Control-Allow-Origin http://www.domain2.com;
add_header Access-Control-Allow-Credentials true;
}
}
Node 中间件代理
Vue 项目中配置 vue.config.js:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://example.com:8080',
changeOrigin: true
}
}
}
}
Express 中使用:
const express = require('express')
const proxy = require('http-proxy-middleware')
const app = express()
app.use('/', proxy({
target: 'http://example.com:8080',
changeOrigin: true,
onProxyRes: function(proxyRes, req, res) {
res.header('Access-Control-Allow-Origin', 'http://example.com')
res.header('Access-Control-Allow-Credentials', 'true')
}
}))
JSONP
利用 <script> 标签不受同源策略限制的特性:
let script = document.createElement('script')
script.src = 'http://example.com/api?callback=handleCallback'
document.body.appendChild(script)
function handleCallback(res) {
console.log(res)
}
服务器返回:
handleCallback({ code: 200, data: [] })
缺点:只支持 GET 请求,存在 XSS 风险。
WebSocket
WebSocket 协议不实行同源策略,使用 ws:// 或 wss:// 前缀。服务器可通过请求头的 Origin 字段判断是否允许通信。
postMessage
用于跨域通信场景:页面与新窗口、多窗口之间、页面与 iframe 之间。
// 发送方
targetWindow.postMessage(data, 'http://example.com')
// 接收方
window.addEventListener('message', function(e) {
if (e.origin === 'http://example.com') {
console.log(e.data)
}
})
Cookie 跨域处理
通过 SameSite 属性控制:
Set-Cookie: session=123; SameSite=None; Secure
SameSite 取值:
Strict:完全禁止第三方 CookieLax:允许 a 标签跳转、link 标签、GET 表单提交None:允许跨域发送,但必须配合 Secure(仅 HTTPS)
Chrome 80 后默认值从 None 改为 Lax。
关键点
- 跨域是浏览器的同源策略限制,请求能发出但响应被拦截
- CORS 是最标准的方案,分简单请求和非简单请求(需预检)
- 开发环境常用 Nginx 或 Node 中间件代理,生产环境用 CORS
- JSONP 只支持 GET 请求,已逐渐被 CORS 替代
- Cookie 跨域需设置 SameSite 属性,Chrome 80 后默认为 Lax
目录