理解 CORS

更新于 2026-01-04

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 机制支持浏览器与服务器之间安全地进行跨源请求和数据传输。现代浏览器在使用 XMLHttpRequestFetch 等 API 时,会利用 CORS 来降低跨源 HTTP 请求带来的安全风险。

👉 查看完整列表:哪些请求会使用 CORS?

它是如何工作的?

当浏览器发起一个跨源请求时,会在请求中包含一个 Origin 头部。服务器则在响应中返回一个 Access-Control-Allow-Origin 头部。如果该响应头的值与请求中的 Origin 匹配,浏览器就允许前端代码访问响应数据;如果不匹配,浏览器就会阻止访问,并抛出 CORS 错误。 CORS 成功流程图 CORS 失败流程图

对于使用 GETPOSTHEAD 以外的方法,或包含非标准头部的请求,必须先进行 预检(preflight)。在这种情况下,浏览器会在发送实际请求前,先发出一个使用 OPTIONS 方法的预检请求。服务器必须在响应中包含 Access-Control-Allow-OriginAccess-Control-Allow-Methods 头部。只有当这些头部的值与请求的源和方法匹配时,浏览器才会继续发送实际请求。

这种机制确保服务器明确允许这些“特殊”请求后再处理它们,从而防止对服务器数据造成意外修改。

CORS 预检成功流程图
CORS 预检失败流程图

虽然 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(网络) 标签页,检查响应头:

  1. 确保服务器响应中包含 Access-Control-Allow-Origin 头部,且其值与请求中的 Origin 头部匹配。
  2. 如果请求需要预检,验证响应是否包含 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,而开发工具则完全忽略它。