跨域配置
浏览器的跨域(Cross-Origin)问题源于浏览器的同源策略(Same-Origin Policy),这是一种重要的安全机制。以下从原理、限制、解决方案等方面详细解析:
一、同源策略:跨域限制的根源
1. 什么是同源?
当两个URL的协议(Protocol)、域名(Domain)、端口(Port) 完全相同时,视为同源。例如:
- 同源:
https://example.com
与https://example.com/path
- 跨域:
https://example.com
与http://example.com
(协议不同) - 跨域:
https://example.com
与https://api.example.com
(域名不同) - 跨域:
https://example.com:8080
与https://example.com:80
(端口不同)
2. 同源策略的限制范围
同源策略限制以下跨域操作:
- AJAX/Fetch请求:无法直接获取跨域接口的响应数据。
- DOM访问:无法读取跨域页面的DOM节点(如iframe嵌套的页面)。
- Cookie/Session:跨域请求时无法自动携带同源的Cookie。
二、跨域请求的常见场景
- 前后端分离开发:前端运行在
http://localhost:3000
,后端API在http://api.example.com
。 - 第三方服务集成:页面嵌入其他域名的API(如地图、支付接口)。
- CDN资源加载:CSS/JS/图片等资源来自不同域名的CDN(例外:浏览器对静态资源的跨域限制较宽松,但某些操作仍受限)。
三、跨域问题的具体表现
当浏览器发起跨域请求时,控制台会报错:
Access to fetch at 'https://api.example.com/data' from origin 'https://your-site.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
核心原因:服务器未返回允许跨域的响应头,浏览器拒绝解析响应数据。
四、跨域解决方案
1. 最推荐方案:CORS(跨域资源共享)
原理:通过服务器返回特定响应头,告知浏览器允许跨域请求。
服务器配置(以Node.js为例):
const express = require('express');
const app = express();
// 允许所有域名跨域(开发环境可用,生产环境建议指定具体域名)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*'); // * 表示允许所有域名
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 允许携带Cookie时,不能使用*,需指定具体域名
// res.setHeader('Access-Control-Allow-Origin', 'https://your-site.com');
// res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
});
关键响应头说明:
Access-Control-Allow-Origin
:允许的源(域名),*
表示所有域名。Access-Control-Allow-Credentials
:是否允许携带Cookie(需与Origin
配合,不能用*
)。Access-Control-Allow-Methods
:允许的HTTP方法(如GET、POST)。Preflight请求
:复杂请求(如PUT、自定义头)会先发送OPTIONS预检请求,服务器需响应允许的策略。
2. 兼容旧浏览器:JSONP(JSON with Padding)
原理:利用<script>
标签无跨域限制的特性,动态加载跨域数据。
前端实现:
function fetchData(url, callback) {
const script = document.createElement('script');
script.src = `${url}?callback=jsonpCallback`;
document.body.appendChild(script);
// 定义回调函数
window.jsonpCallback = function(data) {
callback(data);
document.body.removeChild(script);
delete window.jsonpCallback;
};
}
// 使用示例
fetchData('https://api.example.com/jsonp', (data) => {
console.log(data);
});
服务器响应:
// 响应内容需包裹在回调函数中
jsonpCallback({ "data": "success" });
局限性:
- 仅支持GET请求,无法发送POST等其他方法。
- 存在XSS风险(需确保回调函数名不被篡改)。
3. 前端代理:开发环境常用(如Webpack、Vite)
原理:在开发服务器中设置代理,将跨域请求转发到目标服务器,规避浏览器限制。
Vite代理配置示例(vite.config.js):
export default {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
};
前端请求:
fetch('/api/data').then(res => res.json()); // 实际请求 https://api.example.com/data
适用场景:仅用于开发环境,生产环境需配合后端代理或CORS。
4. 后端代理
原理:在服务器端(如Nginx)设置反向代理,将跨域请求转发至目标域名。
Nginx配置示例:
server {
listen 80;
server_name your-site.com;
location /api/ {
proxy_pass https://api.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
5. 其他方案(较少用)
- PostMessage:用于iframe跨域通信,通过
window.postMessage
传递数据。 - Node中间层:前端请求本地Node服务,由Node服务转发跨域请求(适用于前后端同构项目)。
- WebSocket:基于TCP协议,不受同源策略限制,但需服务器支持WebSocket协议。
五、跨域携带Cookie的注意事项
- 前端需设置
withCredentials: true
:
fetch('https://api.example.com', {
method: 'GET',
credentials: 'include' // 携带同源Cookie
});
- 服务器响应头需满足:
Access-Control-Allow-Origin
不能为*
,必须指定具体域名。- 必须包含
Access-Control-Allow-Credentials: true
。
六、跨域资源加载(静态资源)
浏览器对CSS、JS、图片等静态资源的跨域限制较宽松,但某些操作仍需处理:
- 跨域脚本执行:默认允许加载,但无法通过
document.scripts
获取内容。 - 跨域图片用于Canvas:若图片跨域且未设置
Cross-Origin
头,Canvas会被污染,无法导出。 - 解决方案:服务器为静态资源添加
Access-Control-Allow-Origin
头。
七、总结:跨域的核心原则
- 同源策略是浏览器的安全基石,跨域限制是为了防止恶意网站窃取用户数据。
- 解决方案的核心在服务器:无论是CORS、代理还是JSONP,都需要服务器配合。
- 开发环境与生产环境的策略差异:开发时可用前端代理,生产环境建议使用CORS或后端代理。
- 安全性优先:避免在生产环境使用
Access-Control-Allow-Origin: *
,应指定具体域名,并谨慎处理Cookie。
理解跨域原理后,可根据项目需求选择合适的方案,平衡安全性和开发效率。