前端开发几乎人人都遇到过这个报错:Access to fetch at '...' from origin '...' has been blocked by CORS policy。然后去后端加个 Access-Control-Allow-Origin: *,能跑了,收工。但这么做留下两个问题:为什么会被拦?加 * 安全吗?
这一篇把 CORS(跨域资源共享)讲透。
先搞清:CORS 是浏览器的限制,不是服务器的
第一个要纠正的认知:CORS 报错是浏览器报的,不是服务器拒绝的。
服务器其实正常处理了请求、正常返回了响应。但浏览器拿到响应后,检查响应头里有没有 CORS 允许的字段,没有就把响应拦下来不给页面,并在控制台报错。
为什么要这么设计?因为浏览器的核心安全策略叫同源策略(Same-Origin Policy):一个源(协议+域名+端口)的页面,默认不能读另一个源的响应。这防止了恶意网站读取你在其他网站的数据。
但很多合法场景需要跨域(前后端分离、CDN 资源、第三方 API),所以有了 CORS:服务器通过响应头显式声明「我允许哪个源跨域访问」,浏览器看到允许就放行。
同源:协议+域名+端口完全一致
判断是否跨域,先判断是否「同源」。同源要求三者完全一致:
https://rubyfun.cn/page和https://rubyfun.cn/api—— 同源(路径不同不影响)https://rubyfun.cn和http://rubyfun.cn—— 跨域(协议不同)https://rubyfun.cn和https://api.rubyfun.cn—— 跨域(域名不同,子域也算不同源)https://rubyfun.cn:443和https://rubyfun.cn:8080—— 跨域(端口不同)
只要有一个不同,就是跨域,就受 CORS 约束。
简单请求 vs 预检请求
CORS 把跨域请求分两类,处理方式不同:
简单请求:满足条件(method 是 GET/HEAD/POST,没有自定义 header,Content-Type 限于几种)的请求。浏览器直接发,服务器响应里带 Access-Control-Allow-Origin 就放行。
预检请求(Preflight):不满足简单请求条件(比如 method 是 PUT/DELETE,或有自定义 header 如 Authorization)。浏览器先发一个 OPTIONS 请求问服务器「让不让」,服务器回答允许后,浏览器才发真正的请求。第 3 篇讲 OPTIONS 时详细说过这个流程。
为什么要有预检?因为简单请求会直接到达服务器执行。如果是 DELETE 这种危险操作,没有预检的话,服务器已经执行了删除,浏览器再发现 CORS 不允许也来不及。预检先问再执行,给了一个「撤销机会」。
CORS 的整套响应头
服务器要返回一组头才能让跨域请求通过:
Access-Control-Allow-Origin: https://rubyfun.cn—— 允许哪个源。可以是指定源,或*(允许所有)。Access-Control-Allow-Methods: GET, POST, PUT—— 允许哪些 method。Access-Control-Allow-Headers: Authorization, Content-Type—— 允许哪些自定义请求头。Access-Control-Allow-Credentials: true—— 是否允许带 Cookie。注意:如果设了 true,Allow-Origin不能是*,必须是指定源。Access-Control-Max-Age: 3600—— 预检结果缓存多久,避免每次都预检。
那个危险的 Access-Control-Allow-Origin: *
回到开头的问题:加 * 安全吗?取决于场景。
- 公开 API(天气数据、公开内容):
*没问题,本来谁都能访问。 - 带认证的 API(用户数据):
*危险。因为*配合Allow-Credentials: true是被禁止的(浏览器不允许),所以带 Cookie 的请求用*反而过不了。正确做法是指定具体源:Access-Control-Allow-Origin: https://rubyfun.cn。
盲目加 * 是 CORS 最常见的误用。它对公开数据无害,对私有数据是安全漏洞。
取舍与边界
CORS 有几个值得注意的边界:
- CORS 只管浏览器。curl、Postman、服务端请求不受 CORS 限制——它们不是浏览器,没有同源策略。所以「CORS 报错只在浏览器出现」,用 curl 测试接口永远通,到浏览器就报错,这是正常的。
- 预检请求要正确响应。很多后端框架默认不处理 OPTIONS,导致预检请求 404,真正的请求发不出去。要确保 OPTIONS 被正确路由并返回 CORS 头。
- CORS 不替代认证。CORS 只管「浏览器让不让跨域」,不管「用户有没有权限」。即使 CORS 放行了,该有的认证(Cookie/Token)还是要做。
收束:CORS 是浏览器的跨域闸门
CORS 是浏览器实现的跨域安全机制。它让服务器能显式声明「允许谁跨域访问」,在不破坏同源策略的前提下支持合法的跨域场景。理解了「CORS 是浏览器的限制」和「简单请求 vs 预检」,你才不会只会加 * 而不知道为什么。
下一篇讲 CSP——怎么防止页面被注入恶意脚本(XSS),这是另一个浏览器安全机制。
关于十三Tech
我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。
我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。
如果你想继续跟完这套「图解 HTTP」,欢迎关注公众号 「十三Tech」。后续会按 URL 与报文、连接与传输、缓存与协商、安全与边界、HTTP/2 与 HTTP/3 这条线更新。

