项目中遇到浏览器跨域前端和后端解决方案以及大概过程
前言:
浏览器出于安全考虑,要求请求的 协议(HTTP/HTTPS)、域名、端口(如 90
/455
) 三者完全一致,否则视为跨域。跨域问题的本质是 浏览器通过同源策略保护用户数据安全,强制要求前后端资源同源。开发中因为环境分离、多域名部署等场景就会触发该策略的拦截机制。
一. 纯前端解决方案
1. 本地开发环境推荐使用代理解决
1.在Vue/React项目中配置 vue.config.js
或 webpack.config.js
(vue3中是vite.config.ts
文件)
//vue3的Vite示例
export default defineConfig({
// 服务端渲染
server: {
// 端口号
port: "8980",
host: "0.0.0.0",
// 本地跨域代理 http://192.145.1.95:1216
proxy: {
"/admin-api": {
// 这里填写后端地址
// target: "https://test.com",
target: VITE_API_PATH, //或者封装起来
changeOrigin: true,
rewrite: path => path.replace(/^\/admin-api/, ""),
secure: false // 验证 SSL 证书
}
},
},
});
// vue2的webpack示例示例
module.exports = {
devServer: {
proxy: {
'/admin-api': {
target: 'https://test.com',
changeOrigin: true
}
}
}
};
// 不同的前端语言大致实现思路都一样
2.重启开发服务器,前端请求本地路径包含 /api
自动代理到后端接口地址。
2. 利用WebSocket协议解决
WebSocket 解决跨域的核心原理是在 HTTP 握手阶段通过服务器主动验证 Origin 字段完成跨域授权,而非依赖浏览器同源策略的默认拦截机制
1.前端使用WebSocket建立连接:
const socket = new WebSocket('ws://test.com:9090');
socket.onmessage = (event) => { console.log(event.data); };
2.后端需实现WebSocket服务端(如Socket.io)。
3.postMessage(跨窗口通信)
1.父窗口向iframe子窗口发送消息
const iframe = document.getElementById('child-frame');
iframe.contentWindow.postMessage('data', 'http://child.com');
2.子窗口监听消息:
window.addEventListener('message', (event) => {
if (event.origin === 'http://parent.com') console.log(event.data);
});
二. 后端解决方案
1. CORS(跨域资源共享)--->生产环境推荐
1.后端在响应头中设置 Access-Control-Allow-Origin
,允许指定源访问:
// Spring Boot示例
@CrossOrigin(origins = "http://localhost:9090")
@GetMapping("/api/data")
public String getData() { /*...*/ }
2.若需携带Cookie,需设置 Access-Control-Allow-Credentials: true
并指定具体源(不能为*
)。
3.预检请求(如PUT、DELETE)需处理OPTIONS方法,返回允许的HTTP方法和头信息。
2. Nginx反向代理--->生产环境推荐
1.在Nginx配置文件中添加代理规则:
server {
listen 90;
server_name frontend.com;
location /api {
proxy_pass http://test.com:9090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
2.重启Nginx服务,使前端通过统一域名访问后端接口
3. JSONP(仅GET请求)
1.前端动态创建<script>
标签,指定回调函数名:
function handleData(data) { /*...*/ }
const script = document.createElement('script');
script.src = 'http://test.com/data?callback=handleData';
document.body.appendChild(script);
2.后端返回包裹回调函数的数据:
handleData({ "result": "success" });
三、其他场景方案
同主域不同子域:设置 document.domain = 'test.com'
(需主域相同)
IE兼容性:使用XDomainRequest对象替代XMLHttpRequest
结尾
推荐方案:生产环境优先使用CORS或Nginx反向代理,开发环境用本地代理更方便快捷(配置简单且无侵入性)
慎用方案:JSONP仅适用于简单GET请求且安全性较低(需注意XSS风险),postMessage适用于特定跨窗口场景。
如果兄弟们还有其他更方便的解决方案欢迎评论区讨论分享,具体实现还需根据项目来定最适合的解决方案