一、跨域问题的由来
前端开发中,跨域问题就像一道绕不开的坎。想象一下,你在自己的网站(比如www.example.com)里想通过 JavaScript 调用另一个网站(比如api.other-site.com)的接口,浏览器会直接拒绝这个请求,并抛出一个错误。这就是著名的同源策略在作祟。
同源策略要求协议、域名、端口三者必须完全相同,否则就是跨域。它的存在是为了安全,防止恶意网站窃取用户数据。但现实中,我们经常需要跨域请求数据,比如调用第三方 API、加载 CDN 资源等。这时候,就需要一些解决方案来绕过这个限制。
二、JSONP:最古老的跨域方案
JSONP(JSON with Padding)是最早的跨域解决方案之一,它巧妙地利用了<script>标签不受同源策略限制的特性。
示例(JavaScript 技术栈)
// 前端代码
function handleResponse(data) {
console.log("获取到的数据:", data);
}
// 动态创建 script 标签,请求 JSONP 接口
const script = document.createElement("script");
script.src = "https://api.other-site.com/data?callback=handleResponse";
document.body.appendChild(script);
// 后端返回的数据格式(假设后端支持 JSONP)
handleResponse({
"name": "张三",
"age": 25
});
优点:
- 兼容性极好,连 IE6 都能用
- 实现简单,不需要后端做复杂配置
缺点:
- 只支持 GET 请求
- 安全性较差,容易遭受 XSS 攻击
- 无法获取 HTTP 状态码,错误处理困难
三、CORS:现代浏览器的标准方案
CORS(Cross-Origin Resource Sharing)是目前最推荐的跨域解决方案,它通过 HTTP 头部让浏览器和服务器进行安全通信。
示例(Node.js 后端 + 前端 JavaScript)
// 后端代码(Node.js + Express)
const express = require("express");
const app = express();
app.use((req, res, next) => {
// 允许来自任何域的请求
res.header("Access-Control-Allow-Origin", "*");
// 允许的 HTTP 方法
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: "这是跨域数据!" });
});
app.listen(3000, () => console.log("服务器已启动"));
// 前端代码(使用 fetch API)
fetch("http://localhost:3000/api/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("请求失败:", error));
优点:
- 支持所有 HTTP 方法(GET、POST、PUT 等)
- 安全性高,可精细控制访问权限
- 现代浏览器广泛支持
缺点:
- 需要后端配合设置响应头
- 某些旧浏览器(如 IE9 及以下)不支持
四、其他跨域方案
除了 JSONP 和 CORS,还有一些其他方案,适用于不同场景:
1. 代理服务器
如果你不能修改后端代码,可以在自己的服务器上搭建一个代理,让前端请求代理服务器,再由代理服务器去请求目标 API。
示例(Nginx 反向代理)
server {
listen 80;
server_name my-proxy.com;
location /api/ {
proxy_pass https://api.other-site.com/;
proxy_set_header Host api.other-site.com;
}
}
2. WebSocket
WebSocket 不受同源策略限制,适合实时通信场景。
const socket = new WebSocket("wss://api.other-site.com/ws");
socket.onmessage = (event) => {
console.log("收到消息:", event.data);
};
五、如何选择合适的方案?
- 简单快速 → JSONP(但尽量别用)
- 现代项目 → CORS(首选)
- 无法修改后端 → 代理服务器
- 实时通信 → WebSocket
六、注意事项
- CORS 的预检请求(Preflight):某些复杂请求(如带自定义头的 POST)会先发 OPTIONS 请求,确保后端正确处理。
- 携带 Cookie:CORS 默认不发送 Cookie,需设置
withCredentials和Access-Control-Allow-Credentials。 - 缓存问题:JSONP 请求可能被缓存,可加随机参数避免。
七、总结
跨域问题看似复杂,但核心思路就几种:绕过限制(JSONP)、标准协议(CORS)、中间层(代理)。现代开发中,CORS 是最佳选择,但也要根据实际情况灵活调整。
评论