跨域原理
介绍
跨域是指浏览器从一个域名的网页去请求另一个域名的资源时,由于浏览器的同源策略限制而产生的问题。同源策略是浏览器的一种安全机制,它限制了不同源之间的交互,以防止潜在的安全风险。理解跨域原理和解决方案对于开发Web应用至关重要。
原理
跨域的核心原理:
- 同源策略:协议、域名、端口三者都相同才被视为同源
- 跨域请求:当请求的目标资源与当前页面不同源时,会触发跨域限制
- 浏览器安全限制:阻止跨域的读写操作,但允许跨域的资源加载(如图片、CSS、JavaScript)
- CORS(Cross-Origin Resource Sharing):W3C标准,允许服务器指定哪些源可以访问其资源
- 跨域解决方案:CORS、JSONP、代理服务器、WebSocket等
图示
同源策略
协议 + 域名 + 端口 必须完全相同
例如:
- http://example.com:80 和 https://example.com:80 不同源(协议不同)
- http://example.com 和 http://www.example.com 不同源(域名不同)
- http://example.com:80 和 http://example.com:8080 不同源(端口不同)
跨域请求流程
客户端 → 发送跨域请求 → 服务器 → 返回响应(带CORS头) → 浏览器检查CORS头 → 允许/拒绝请求
实例
CORS解决方案示例
// 服务器端设置CORS头 (Node.js/Express)
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');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
app.get('/api/data', (req, res) => {
res.json({ message: '跨域请求成功' });
});
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
// 客户端请求 (浏览器)
fetch('http://localhost:3000/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('错误:', error));
JSONP解决方案示例
<!-- 客户端HTML -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONP示例</title>
</head>
<body>
<h1>JSONP跨域请求示例</h1>
<div id="result"></div>
<script>
// 定义回调函数
function handleResponse(data) {
document.getElementById('result').textContent = JSON.stringify(data);
}
// 创建script标签
const script = document.createElement('script');
script.src = 'http://localhost:3000/api/jsonp?callback=handleResponse';
document.body.appendChild(script);
</script>
</body>
</html>
// 服务器端 (Node.js/Express)
app.get('/api/jsonp', (req, res) => {
const callback = req.query.callback;
const data = { message: 'JSONP请求成功' };
const jsonpResponse = `${callback}(${JSON.stringify(data)})`;
res.type('text/javascript').send(jsonpResponse);
});
专业解决方案
跨域解决方案对比
- CORS:标准解决方案,支持所有HTTP方法,安全可靠
- JSONP:仅支持GET方法,不安全,但兼容性好
- 代理服务器:前端无感知,服务器端转发请求
- WebSocket:不受同源策略限制,适用于实时通信
- postMessage:用于iframe间通信
- document.domain:适用于主域相同、子域不同的情况
- location.hash:适用于iframe间通信,安全性较低
CORS详细配置
- Access-Control-Allow-Origin:指定允许的源
- Access-Control-Allow-Methods:指定允许的HTTP方法
- Access-Control-Allow-Headers:指定允许的请求头
- Access-Control-Allow-Credentials:是否允许发送Cookie
- Access-Control-Max-Age:预检请求的缓存时间
- Access-Control-Expose-Headers:允许客户端访问的响应头
安全考虑
- 避免使用通配符
*作为Access-Control-Allow-Origin - 验证Origin头,仅允许可信的源
- 对于带Credentials的请求,Access-Control-Allow-Origin不能为
* - 实现CSRF保护,避免跨站请求伪造
- 对敏感数据使用HTTPS
工具推荐
- cors:Node.js/Express的CORS中间件
- jsonp:JSONP请求库
- http-proxy-middleware:代理服务器中间件
- Axios:支持CORS的HTTP客户端
- Postman:API测试工具,可模拟跨域请求
- Chrome DevTools:Network面板查看CORS请求