JavaScript中的跨域请求与CORS机制
字数 1436 2025-11-16 04:35:00
JavaScript中的跨域请求与CORS机制
1. 跨域问题的来源
同源策略(Same-Origin Policy)是浏览器的一种安全机制,它限制一个源的文档或脚本如何与另一个源的资源进行交互。如果两个URL的协议、域名、端口完全相同,则属于同源;否则属于跨域。例如:
https://a.com和https://b.com→ 跨域(域名不同)http://a.com和https://a.com→ 跨域(协议不同)a.com:80和a.com:8080→ 跨域(端口不同)
同源策略默认阻止跨域读取资源(如通过fetch或XMLHttpRequest请求数据),但允许跨域写入(如表单提交、链接跳转)和嵌入(如<script>、<img>标签)。
2. 常见的跨域解决方案
(1)JSONP(JSON with Padding)
原理:利用<script>标签不受同源策略限制的特性,通过动态创建<script>标签请求一个JS文件,服务器返回一段调用回调函数的JS代码,将数据作为参数传递给回调函数。
示例:
function handleResponse(data) {
console.log("收到数据:", data);
}
// 动态添加<script>标签
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);
缺点:仅支持GET请求,缺乏错误处理机制,存在安全风险(如XSS)。
(2)CORS(跨域资源共享)
CORS是W3C标准,允许服务器声明哪些源可以访问其资源。浏览器在发现跨域请求时,会自动添加Origin头,并根据服务器返回的CORS头决定是否允许访问。
3. CORS的详细机制
(1)简单请求(Simple Request)
需同时满足以下条件:
- 方法为GET、POST、HEAD之一;
- 头部仅允许以下字段:
Accept、Accept-Language、Content-Language、Content-Type(值仅限于application/x-www-form-urlencoded、multipart/form-data、text/plain)。
流程:
- 浏览器直接发送跨域请求,并在
Request Headers中自动添加Origin: https://a.com。 - 服务器检查
Origin,若允许访问,则在响应头中包含:Access-Control-Allow-Origin: https://a.com // 或通配符* Access-Control-Allow-Credentials: true // 可选,允许携带Cookie - 浏览器检查响应头,若
Access-Control-Allow-Origin包含当前源,则允许读取响应。
(2)预检请求(Preflight Request)
不满足简单请求条件的请求(如使用PUT方法或Content-Type: application/json)会先发送一个OPTIONS预检请求。
流程:
- 浏览器自动发送OPTIONS请求,头部包含:
Origin: https://a.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Content-Type - 服务器响应预检请求,返回允许的规则:
Access-Control-Allow-Origin: https://a.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: Content-Type Access-Control-Max-Age: 86400 // 缓存预检结果的时间(秒) - 预检通过后,浏览器才发送实际请求。
4. 实际代码示例
客户端代码(前端)
// 携带Cookie的CORS请求
fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include' // 需服务器设置Access-Control-Allow-Credentials: true
})
.then(response => response.json())
.catch(error => console.error('请求失败:', error));
服务器端代码(Node.js/Express示例)
app.use((req, res, next) => {
const allowedOrigins = ['https://a.com', 'https://b.com'];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 处理预检请求
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
5. 注意事项
- 通配符
*与凭证:若响应头包含Access-Control-Allow-Origin: *,则浏览器不允许携带Cookie(credentials: 'include'会失败)。 - 错误处理:CORS失败时,浏览器会抛出网络错误,需通过
try-catch或Promise的catch捕获。 - 非简单请求的两次请求:实际请求可能被延迟,需注意性能影响。
通过理解CORS的机制,可以安全地实现跨域数据交互,同时避免常见配置错误。