R Bika(s) 2023-04-30
什么是 CORS?
假设一个网站托管在 localhost:8000 上,其 JavaScript 代码尝试向运行在 localhost:9000 的服务器发送请求,那么该请求会因浏览器强制执行的 同源策略(same-origin policy) 而失败。
同源策略限制了从一个源(origin)加载的文档或脚本与来自另一个源的资源进行交互,默认情况下会阻止未经授权的跨源请求。
其工作原理如下:
- 浏览器允许向相同源发起的请求。
- 向不同源发起的请求(即跨源请求)默认会被阻止,并导致 CORS 错误。
那么,CORS 到底是什么?
CORS(Cross-Origin Resource Sharing,跨源资源共享) 是一种基于 HTTP 头部的机制,允许服务器告诉浏览器哪些源被授权访问其资源。
CORS 机制支持浏览器与服务器之间安全地进行跨源请求和数据传输。现代浏览器在使用 XMLHttpRequest 或 Fetch 等 API 时,会利用 CORS 来降低跨源 HTTP 请求带来的安全风险。
👉 查看完整列表:哪些请求会使用 CORS?
它是如何工作的?
当浏览器发起一个跨源请求时,会在请求中包含一个 Origin 头部。服务器则在响应中返回一个 Access-Control-Allow-Origin 头部。如果该响应头的值与请求中的 Origin 匹配,浏览器就允许前端代码访问响应数据;如果不匹配,浏览器就会阻止访问,并抛出 CORS 错误。
对于使用 GET、POST、HEAD 以外的方法,或包含非标准头部的请求,必须先进行 预检(preflight)。在这种情况下,浏览器会在发送实际请求前,先发出一个使用 OPTIONS 方法的预检请求。服务器必须在响应中包含 Access-Control-Allow-Origin 和 Access-Control-Allow-Methods 头部。只有当这些头部的值与请求的源和方法匹配时,浏览器才会继续发送实际请求。
这种机制确保服务器明确允许这些“特殊”请求后再处理它们,从而防止对服务器数据造成意外修改。
虽然
POST方法可以修改服务器数据,但它并不总是触发预检请求。在 CORS 出现之前,浏览器已经允许带有标准头部的跨源POST请求,服务器也已为此类请求做好准备。因此,CORS 的设计初衷并非改变已有行为,而是保护服务器免受那些过去未被考虑的新类型跨源请求的影响。
如何修复 CORS 错误?
让我们回顾文章开头的例子:一个运行在 localhost:8000 的客户端应用向 localhost:9000 的服务器发起请求。如果 CORS 配置不正确,请求将失败,并在浏览器控制台显示如下错误:
Access to fetch at 'http://localhost:9000/api/endpoint' from origin 'http://localhost:8000' has been blocked by CORS policy.
要排查问题,请打开浏览器开发者工具的 Network(网络) 标签页,检查响应头:
- 确保服务器响应中包含
Access-Control-Allow-Origin头部,且其值与请求中的Origin头部匹配。 - 如果请求需要预检,验证响应是否包含
Access-Control-Allow-Methods头部,并确认它允许所使用的 HTTP 方法。
如果缺少必要头部或设置错误,请更新服务器配置以包含正确的 CORS 头部。在 Express.js 应用中,可以轻松使用 cors 中间件实现:
var express = require('express');
var cors = require('cors');
var app = express();
app.use(cors({ origin: 'http://localhost:8000' }));
app.get('/api', function (req, res, next) {
res.json({ msg: 'success' });
});
app.listen(9000, function () {
console.log('CORS-enabled for localhost:8000');
});
🧠 常见误区:调试 CORS 问题时,很多人会困惑为什么在 Postman 或
curl中请求能成功,但在浏览器中却失败。
原因是:CORS 错误只在浏览器中出现。Postman、curl等工具不会发起“跨源请求”——它们只是直接发送网络请求(就像你在新标签页中打开 URL 一样)。
虽然 CORS 是在服务器端配置的,但是否遵守这些规则是由客户端决定的。出于安全考虑,大多数浏览器会强制执行 CORS,而开发工具则完全忽略它。