其实跨域问题是后端来解决的? CORS

其实跨域问题是后端来解决的? CORS

浏览器的同源策略

浏览器 出于安全 考虑,对同源 请求放行 ,对异源 请求限制 ,这些限制规则统称为同源策略 。因此限制造成的开发问题,称之为跨域问题

同源的核心判定标准

同源的判定有且仅有三个必须同时完全匹配的核心要素,缺一不可。只要有一个要素不同,就会被判定为「跨域」。

源的标准格式:协议://域名:端口,路径、查询参数、哈希值不影响同源判定。

核心要素 判定规则 常见注意点
协议(Protocol) 必须完全一致 http 与 https、wss 与 ws,均视为不同协议,直接判定跨域
域名(Domain) 必须精确匹配 根域名与子域名、域名与对应 IP、不同二级域名,均视为不同域名
端口(Port) 必须完全一致 省略端口时,使用协议默认端口(http 默认 80,https 默认 443),默认端口与显式端口不一致也判定跨域
同源判定示例(基准源:http://www.example.com/index.html
待检测 URL 是否同源 核心原因
http://www.example.com/user/info.html 协议、域名、端口完全一致,仅路径不同不影响
https://www.example.com 协议不同(http→https)
http://api.example.com 域名不同(二级域名不一致)
http://www.example.com:8080 端口不同(默认 80→8080)
http://example.com 域名不同(根域名与 www 二级域名不匹配)
http://192.168.1.100 域名与对应 IP 不匹配,即使解析结果一致也不算同源

同源策略的核心限制范围

同源策略的限制,主要集中在数据存储、DOM 访问、网络请求三大核心维度,这也是绝大多数跨域问题的根源。

数据存储的强隔离

不同源的站点之间,无法互相读取 / 写入浏览器端的敏感存储数据,包括:

  • Cookie、SessionStorage、LocalStorage
  • IndexedDB、Web SQL 数据库
  • 加密的媒体资源、缓存文件

例外:Cookie 可通过domain属性放宽至同根域名下的子域名(如设置domain=example.com,则a.example.comb.example.com可共享该 Cookie),同时受SameSiteSecure属性的额外约束。

DOM 节点的访问限制

不同源的页面之间,无法互相操作 DOM 和 JavaScript 对象,典型场景:

  • 父页面无法读取 / 修改<iframe>嵌入的跨域页面的 DOM
  • 跨域 iframe 无法操作父页面的 DOM 和全局 JS 变量
  • window.open打开的跨域新窗口,与原窗口之间无法互相访问 DOM
网络请求的拦截(最常见跨域问题)

浏览器默认禁止前端 JS 通过XMLHttpRequestfetch等 AJAX 方式,发起跨域请求并读取响应内容。

跨域不是请求发不出去,而是浏览器拦截了响应。绝大多数场景下,请求已正常发送到后端并得到响应,只是浏览器发现不符合同源规则、且无合法跨域授权时,会阻止 JS 读取响应数据,并在控制台抛出跨域错误。

同源策略不限制的行为

同源策略并非一刀切禁止所有跨源交互,以下场景不受限制:

  • 带有src/href属性的 HTML 标签资源 加载:<script><img><link><video>、``、<iframe>等,浏览器允许加载跨域资源;但会限制 JS 对加载后内容的读取(如跨域图片无法通过 canvas 读取像素、跨域脚本的报错信息会被脱敏)。
  • 表单的跨域提交:form 表单可直接提交到跨域地址,但提交后原页面无法读取响应内容。
  • 超链接跳转、window.open打开新窗口:可正常跳转跨域地址,但无法操作新窗口的 DOM 和存储数据。
  • WebSocket 协议:本身不受同源策略限制,可自由跨域通信。

CORS跨域请求

后端通过在 HTTP 响应头中添加明确的授权标识,告诉浏览器 "这个跨域请求是被允许的",浏览器识别后就会放行响应数据。

CORS 的两种请求类型

浏览器将 CORS 请求分为简单请求非简单请求,两者的处理流程不同。

简单请求(直接发送,无预检)

同时满足以下两个条件的请求为简单请求:

  • 请求方法 :仅 GETPOSTHEAD 之一

  • 请求头:仅包含以下安全头(无自定义头):

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type(仅允许 text/plainmultipart/form-dataapplication/x-www-form-urlencoded

流程:浏览器直接发送请求,后端返回响应并带上 CORS 头,浏览器检查头后决定是否放行响应。

非简单请求(先预检,再发送)

不满足简单请求条件的均为非简单请求(如 PUT/DELETE 请求、带自定义头的请求、Content-Type: application/json 的请求)。

流程

  1. 预检请求(OPTIONS) :浏览器先自动发送一个 OPTIONS 方法的请求,询问后端 "是否允许该跨域请求"
  2. 后端响应预检 :后端返回 204 No Content 状态码,并带上 CORS 授权头
  3. 正式请求:浏览器收到预检通过的响应后,再发送真正的业务请求
  4. 返回响应:后端处理业务并返回数据

预检请求的作用:在发送可能修改服务器数据的请求前,先确认后端是否允许,避免对服务器造成意外影响。

go 复制代码
func CORS() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 核心三行CORS头
        c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

        // 处理OPTIONS预检
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }
        c.Next()
    }
}
  • Content-Type:前端发 JSON 数据时(比如 axios.post 传对象),会自动带这个头,值是 application/json。如果不允许,后端收不到 JSON 数据。

  • Authorization :前端登录后传 Token 时(比如 Bearer xxx),会带这个头。如果不允许,后端拿不到 Token,验证不了身份。

相关推荐
Harvy_没救了1 小时前
【网络架构】Keepalived + LVS(DR) + MariaDB 双主备实践
网络·架构·lvs
爱学习的小囧7 小时前
ESXi 8.0 原生支持 NVMe 固态硬盘吗?VMD 配置详解教程
linux·运维·服务器·esxi·esxi8.0
大鹏说大话7 小时前
SSL证书自动化的未来:ACME协议与Let’s Encrypt实践
网络·安全
坚持就完事了7 小时前
Linux中的变量
linux·运维·服务器
Cat_Rocky8 小时前
利用Packet Tracer网络实验
linux·运维·服务器
被摘下的星星8 小时前
网际协议(IP协议)
网络·tcp/ip
爱学习的小囧9 小时前
ESXi VMkernel 端口 MTU 最佳设置详解
运维·服务器·网络·php·虚拟化
不会写DN9 小时前
Golang中的map的key可以是哪些类型?可以嵌套map吗?
后端·golang·go