FSA全栈行动 FSA全栈行动
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
  • 内功心法

    • 《深入浅出设计模式Java版》笔记
前端
后端
  • 产品
  • 代理
  • 提效
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr

公众号:FSA全栈行动

记录学习过程中的知识
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
  • 内功心法

    • 《深入浅出设计模式Java版》笔记
前端
后端
  • 产品
  • 代理
  • 提效
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr
  • Linux音视频

  • Docker

  • Http

    • 别再盲目复制了:彻底搞懂 CORS 的本质与那些“神坑”
      • 一、前言
      • 二、核心原理:它到底在保护谁?
        • 1、CORS 的本质:一个“保镖”机制
        • 2、什么是“源” (Origin)?
      • 三、实战避坑:为什么你的请求总是“莫名其错”?
        • 1、Postman 与浏览器的差异
        • 2、深坑:预检请求 Preflight
        • 3、那些高阶的“神坑”
      • 四、总结
  • Python环境

  • Python爬虫

  • 后端
  • Http
GitLqr
2026-07-23
目录

别再盲目复制了:彻底搞懂 CORS 的本质与那些“神坑”

欢迎关注微信公众号:[FSA全栈行动 👋]

# 一、前言

说实话,我以前遇到 CORS 报错时的反应非常典型:直接把那串红色的报错信息复制,扔进 Google。然后,在成千上万个 Stack Overflow 回答里找一个点赞最高的,直接把 Access-Control-Allow-Origin: * 复制到我的 Express 服务里,就搞定了,收工。

但是,空闲之后复盘,却发现对此头信息的底层逻辑一问三不知,为什么这个接口之前没加此头信息时,在 Postman 里能调通,在浏览器里就报 CORS 错误?

所以,我决定静下心来把这件事彻底拆解清楚。如果你也还在通过“复制粘贴”来解决 CORS 问题,建议你花几分钟看完这篇,这能让你少走很多弯路。

# 二、核心原理:它到底在保护谁?

很多人初学时会有一种误区,觉得 CORS 是为了保护服务器的安全(比如防止非法请求)。

其实不然。CORS 的核心逻辑是:它不是为了给服务器筑起防火墙,而是为了给“浏览器里的用户”当保镖。

# 1、CORS 的本质:一个“保镖”机制

你可以把 CORS 想象成一个专门为“访客”服务的保安。

你的浏览器里存着非常敏感的信息,比如 Cookies、Session、或者某个站点的 Auth Token。当一个网页(比如 myapp.com)尝试向另一个域名的服务器(比如 api.other.com)发送请求时,浏览器会非常谨慎。

浏览器会问服务器一个问题:“这个来自 myapp.com 的网页,你真的允许它代表用户来访问你吗?”

默认情况下,浏览器的回答是:“除非你明确说允许,否则统统不行。”这就是所谓的“同源策略”(Same-Origin Policy)。而 CORS 则是服务器用来表达“我允许这个页面访问”的一种手段。

# 2、什么是“源” (Origin)?

要搞懂 CORS,首先得知道什么是“同源”。一个“源”由三个部分组成:

  1. 协议 (Protocol)

  2. 域名 (Domain)

  3. 端口 (Port)

只要这三者中任何一个不同,它们就是不同的源。

场景

原始 URL

目标 URL

结论

原因

协议不同

https://example.com

http://example.com

不同源

https vs http

域名不同

https://a.com

https://b.com

不同源

域名不一致

端口不同

http://localhost:3000

http://localhost:8080

不同源

端口不一致

IP vs 域名

http://127.0.0.1

http://localhost

不同源

虽然指向同一设备,但在浏览器眼中它们不同

# 三、实战避坑:为什么你的请求总是“莫名其错”?

在实际开发中,CORS 的坑通常藏在那些你看不见的地方。

# 1、Postman 与浏览器的差异

这是最让新手困惑的地方:为什么 Postman 调用接口顺畅无比,浏览器却报 CORS 错误?

原因非常简单:Postman 和 curl 这类工具不是浏览器。

它们不遵循浏览器的安全限制,也不会去执行什么“同源策略”。它们直接发请求,服务器也直接回响应。但浏览器不同,它在收到响应后会先“过一遍”安全检查,如果发现没有 CORS 相关的头部信息,它会直接把结果拦下来,不让你在 JavaScript 里读到。

# 2、深坑:预检请求 Preflight

很多时候,你的 Backend 日志里根本看不到报错的那个请求。这是因为浏览器在发送真正的请求前,会先悄悄发一个“探测请求”,这就是 Preflight(预检请求),使用的 HTTP 方法是 OPTIONS。

当你使用了以下内容时,浏览器会自动触发预检请求:

  • 使用了非简单方法(如 PUT、DELETE)。

  • 设置了自定义的 Header(如 Authorization)。

  • Content-Type 不是简单的 application/x-www-form-urlencoded、multipart/form-data 或 text/plain(比如现在最常用的 application/json)。

如果你的服务器没有正确响应这个 OPTIONS 请求(必须返回 Access-Control-Allow-Origin 等头部),那么真实的业务请求压根就不会发出去。你以为是业务逻辑崩了,其实是预检都没过。

# 3、那些高阶的“神坑”

在生产环境,我见过无数团队在这些地方折腾一整天:

  • “万能”但危险的 Wildcard (*): 很多人喜欢用 Access-Control-Allow-Origin: *。这在纯公开的 API(不需要 Cookie 或 Authorization)中没问题,但如果你需要携带凭证(Credentials),浏览器会直接拒绝这种组合。你必须明确指定具体的 Origin。

  • 错误响应也需要 CORS 头部: 这是一个极大的隐蔽坑。如果你的后端逻辑出错抛出了 500 Error,而你的错误处理中间件在返回错误时忘记加上 CORS 头部,浏览器会因为拿不到 CORS 头部而报出一个“CORS error”。这会让你误以为是权限问题,其实是你的业务代码崩了。

  • 重定向陷阱: 如果你的 OPTIONS 请求遇到了 301 或 302 重定向(比如从 http 跳到 https),预检请求通常会直接失败。

  • 代理与 Nginx 的覆盖: 有时候你在 Express 里配得好好的,但依然报错。这时候要检查一下,是不是前端前面的 Nginx、API Gateway 或者 CDN 把你的 CORS 响应头给拦截或者覆盖掉了。

# 四、总结

处理 CORS 的最高境界不是学会如何“绕过”它,而是学会如何“正确地配置”它。

一旦你明白 CORS 本质上是一个关于“信任”的机制,你的调试思路就会发生变化:

  1. 不要再盲目复制 *。

  2. 重点关注 Network 标签页里的 OPTIONS 请求。

  3. 确保所有的响应(包括错误响应)都能带上正确的 CORS 头部。

如果你的项目涉及到多域名访问,建议在后端维护一个 Allowlist(允许列表),根据请求的 Origin 动态返回匹配的 Access-Control-Allow-Origin,而不是简单地回一个 *。

最后,如果你在折腾 CORS 时遇到了什么让你抓狂的奇葩问题,欢迎在评论区交流。

#跨域#CORS#OPTIONS#Origin
上次更新: 2026/07/26, 08:42:07
Docker - Compose的使用
Python-虚拟环境

← Docker - Compose的使用 Python-虚拟环境→

最近更新
01
给 Flutter 插件加上 Swift Package Manager 支持
07-26
02
Flutter 3.44 性能飞跃:深度解析 Android Platform View 的 HCPP 新特性
07-25
03
别在 Flutter 的 main() 里乱锁屏幕方向,小心 iPad 分屏功能被你搞没了
07-24
更多文章>
Theme by Vdoing | Copyright © 2020-2026 FSA全栈行动
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×