一、什么是前端跨域?
跨域的本质是浏览器的同源策略(Same-Origin Policy) 限制:浏览器为了安全,只允许当前页面请求「同源」的资源,当请求的资源和当前页面的「源」不一致时,就会触发跨域限制。
「同源」的判断标准是:协议、域名、端口 三者必须完全一致。
举个例子:当前页面地址是 http://www.example.com:8080,以下请求会被判定为跨域:
https://www.example.com:8080(协议不同:http vs https)http://blog.example.com:8080(域名不同:www vs blog)http://www.example.com:8081(端口不同:8080 vs 8081)
二、同源策略主要限制哪些方面?
同源策略的限制集中在「数据层面」,核心是防止恶意网站窃取其他网站的敏感数据,主要限制以下行为:
1. AJAX/fetch 请求跨域
这是最常见的跨域限制:前端通过 XMLHttpRequest 或 fetch 向不同源的后端接口发请求时,浏览器会拦截响应,控制台报错(如 Access to fetch at 'xxx' from origin 'xxx' has been blocked by CORS policy)。
2. DOM 访问限制
无法操作不同源页面的 DOM,比如:
- 嵌入的跨域 iframe,父页面无法获取 iframe 内的
document、window等对象; - 跨域的 window.open 打开的新窗口,无法互相访问数据。
3. Cookie/LocalStorage 等存储限制
不同源的页面无法共享 Cookie、LocalStorage、SessionStorage 等存储数据,比如 A 网站的 Cookie 无法被 B 网站读取。
4. 其他限制
- 跨域脚本无法获取
indexedDB数据; - WebSocket 虽然本身不严格跨域,但也受同源策略的间接限制(需服务端配合)。
三、跨域问题的解决方案
不同的跨域场景对应不同的解决方案,以下是最常用、最符合现代开发规范的方案:
方案1:CORS(跨域资源共享)—— 推荐首选
这是后端主导的解决方案,也是最标准、最安全的方式,核心是后端在响应头中添加允许跨域的配置。
原理
后端在返回响应时,设置 Access-Control-Allow-Origin 等响应头,明确告诉浏览器「允许哪些源访问该资源」。(控制权在后端,所以说是由后端主导。)
示例(以 Node.js/Express 为例)
const express = require('express');
const app = express();
// 全局跨域中间件
app.use((req, res, next) => {
// 允许指定源(生产环境建议精准配置,不要用*)
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
// 允许携带Cookie(需配合前端withCredentials: true)
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 允许的请求方法
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
// 允许的请求头
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 处理预检请求(OPTIONS)
if (req.method === 'OPTIONS') {
return res.sendStatus(204); // 预检请求无需返回内容
}
next();
});
// 测试接口
app.get('/api/data', (req, res) => {
res.json({ code: 200, data: '跨域请求成功' });
});
app.listen(8080, () => {
console.log('服务运行在8080端口');
});
前端请求示例(fetch)
fetch('http://localhost:8080/api/data', {
method: 'GET',
credentials: 'include' // 携带Cookie(需后端允许)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
方案2:前端代理(开发环境专用)
开发阶段(如 Vue/React 项目),可以通过本地代理绕过跨域限制,核心是「让前端请求先发到本地服务器,再由本地服务器转发到目标后端」(服务器之间请求无跨域限制)。
示例(Vue项目,vue.config.js)
module.exports = {
devServer: {
proxy: {
// 匹配以/api开头的请求
'/api': {
target: 'http://localhost:8080', // 目标后端地址
changeOrigin: true, // 开启跨域代理
pathRewrite: { '^/api': '' } // 去掉请求路径中的/api前缀(可选)
}
}
}
};
此时前端请求只需写本地路径:
// 实际请求会被代理到 http://localhost:8080/data
fetch('/api/data').then(res => res.json());
方案3:JSONP(仅支持GET请求,不推荐)
这是早期的跨域方案,利用 <script> 标签不受同源策略限制的特性,仅支持 GET 请求,安全性和灵活性较差,仅适用于老项目兼容。
示例
后端代码(Node.js):
app.get('/api/jsonp', (req, res) => {
const { callback } = req.query; // 获取前端传的回调函数名
const data = { code: 200, data: 'JSONP跨域成功' };
res.send(`${callback}(${JSON.stringify(data)})`); // 返回回调函数调用
});
前端代码:
function handleJsonpData(data) {
console.log(data); // 接收后端返回的数据
}
// 动态创建script标签
const script = document.createElement('script');
script.src = 'http://localhost:8080/api/jsonp?callback=handleJsonpData';
document.body.appendChild(script);
方案4:其他补充方案
- nginx反向代理:生产环境常用,通过nginx配置转发请求,原理和前端代理一致,由服务器层解决跨域;
- postMessage:用于解决跨域页面间的通信(如iframe、多窗口),而非AJAX请求;
- WebSocket:本身不受同源策略限制,可用于跨域实时通信。
总结
- 跨域本质:浏览器的同源策略限制,核心是保护用户数据安全,判断标准是「协议、域名、端口」三者一致;
- 主要限制:AJAX请求、DOM访问、Cookie/存储共享是最核心的限制点;
- 核心解决方案:生产环境优先用「CORS(后端配置)」,开发环境用「前端代理」,JSONP仅作为老项目兼容方案。