跨域(CORS)的几种方式
1. CORS(跨域资源共享)
原理:服务器设置 HTTP 响应头,允许指定来源访问资源。
适用场景:前后端分离项目(主流方案)。
服务器端设置(以 Node.js 为例)
const express = require('express');
const app = express();// 允许所有来源访问(生产环境应限制为具体域名)
app.use((req, res, next) => {res.header('Access-Control-Allow-Origin', '*'); // 或 'https://example.com'res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');next();
});app.get('/api/data', (req, res) => {res.json({ message: 'CORS 允许跨域访问' });
});app.listen(3000);
说明:
-
Access-Control-Allow-Origin
:允许的域名(*
表示所有)。 -
Access-Control-Allow-Methods
:允许的 HTTP 方法。 -
Access-Control-Allow-Headers
:允许的请求头。
2. JSONP(仅 GET 请求)
原理:利用 <script>
标签不受同源策略限制的特性,动态创建 script
请求数据。
适用场景:仅支持 GET 请求,老旧浏览器兼容方案。
前端代码
function jsonp(url, callbackName) {const script = document.createElement('script');script.src = `${url}?callback=${callbackName}`;document.body.appendChild(script);
}// 定义回调函数
function handleResponse(data) {console.log('JSONP 返回数据:', data);
}// 调用 JSONP
jsonp('http://example.com/api/data', 'handleResponse');
服务器端代码(Node.js)
app.get('/api/data', (req, res) => {const callbackName = req.query.callback;const data = { message: 'JSONP 返回数据' };res.send(`${callbackName}(${JSON.stringify(data)})`);
});
缺点:
-
仅支持 GET 请求。
-
安全性较低(容易遭受 XSS 攻击)。
3. 代理服务器(Proxy)
原理:前端请求同域代理服务器,代理服务器转发请求到目标服务器。
适用场景:开发环境(如 webpack-dev-server
)或 Nginx 反向代理。
(1)Webpack DevServer 代理
// vue.config.js / webpack.config.js
module.exports = {devServer: {proxy: {'/api': {target: 'http://example.com', // 目标服务器changeOrigin: true, // 修改请求头 HostpathRewrite: { '^/api': '' }, // 重写路径},},},
};
前端请求 /api/data
会被代理到 http://example.com/data
。
(2)Nginx 反向代理
server {listen 80;server_name localhost;location /api {proxy_pass http://example.com; # 目标服务器proxy_set_header Host $host;}
}
访问 http://localhost/api/data
会被代理到 http://example.com/api/data
。
4. WebSocket
原理:WebSocket 不受同源策略限制,可用于跨域通信。
适用场景:实时通信(如聊天室、股票行情)。
前端代码
const socket = new WebSocket('ws://example.com/socket');socket.onmessage = (event) => {console.log('WebSocket 消息:', event.data);
};
服务器端(Node.js + ws 库)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', (ws) => {ws.send('WebSocket 连接成功');
});
5. postMessage(跨窗口通信)
原理:window.postMessage
允许不同源的窗口间通信。
适用场景:iframe 跨域通信、多窗口交互。
父窗口(http://parent.com)
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello from parent!', 'http://child.com');
子窗口(http://child.com)
window.addEventListener('message', (event) => {if (event.origin !== 'http://parent.com') return; // 验证来源console.log('收到消息:', event.data);
});
6. document.domain(仅适用于主域相同)
原理:修改 document.domain
使子域之间可以通信。
适用场景:a.example.com
和 b.example.com
之间的通信。
前端代码
// 在 a.example.com 和 b.example.com 都设置
document.domain = 'example.com';
限制:
-
仅适用于主域相同的情况(如
a.example.com
和b.example.com
)。 -
现代浏览器已逐渐废弃此方法。
7. 浏览器禁用安全策略(仅开发环境)
方法:启动浏览器时关闭安全策略(不推荐生产环境使用)。
示例(Chrome):
chrome.exe --disable-web-security --user-data-dir="C:\Temp"
风险:可能导致安全问题,仅用于本地测试。
总结
推荐方案:
-
生产环境:使用 CORS(主流方案)或 Nginx 代理。
-
开发环境:使用 Webpack 代理 或 CORS。
-
特殊需求:WebSocket(实时通信)、postMessage(跨窗口通信)。