Origin 和 Referer 的区别

March 22, 2023

前言

在前端开发中,跨域问题几乎是每个开发者都会遇到的"老朋友"。但你是否遇到过这样的怪事:同一个 CDN 域名,图片资源可以正常加载,视频资源却返回 403 Forbidden?更奇怪的是,直接在浏览器新标签页打开视频链接,视频又能正常播放。

本文将从一个真实案例出发,深入剖析浏览器对不同资源类型的跨域处理机制,彻底搞懂 OriginReferer 请求头的区别,以及如何正确配置 CDN 解决此类问题。

背景:一个诡异的 403 问题

在 localhost 开发环境中,我遇到了一个奇怪的现象:

现象一:图片资源正常加载

请求 URL: https://cdn.xxxx.com/images/example.png
请求头:
  Referer: http://localhost:5173/
  ( Origin )
响应: 200 OK

现象二:视频资源 403

请求 URL: https://cdn.xxxx.com/videos/example.mp4
请求头:
  Origin: http://localhost:5173
  Referer: http://localhost:5173/
响应: 403 Forbidden

现象三:直接访问视频链接正常

  • 在浏览器新标签页直接打开 https://cdn.xxxx.com/videos/example.mp4,视频可以正常播放

这就引发了几个疑问:

  1. 为什么同一个 CDN,图片只有 Referer 头,视频却同时有 OriginReferer 头?
  2. 为什么直接访问视频 URL 可以,页面中加载却 403?
  3. 这和 CDN 配置有什么关系?

核心原因分析

这个差异和 CDN 无关,是浏览器对不同媒体资源的跨域加载机制、CORS(跨域资源共享)规则的天然区别导致的——图片是「简易跨域资源」仅带Referer,视频是「需强CORS校验的资源」会同时带Origin+Referer,这也是本地image能访问CDN、video报403的核心原因(CDN/源站只校验了Referer却没配置CORS,拦截了带Origin的视频请求)。

浏览器对不同资源的跨域加载逻辑

浏览器为了安全和资源特性,对图片、字体、脚本这类「被动加载资源」和视频、音频、Fetch/AJAX这类「主动加载/可跨域读写的资源」制定了不同的跨域规则,直接导致请求头的差异,这是HTML5和CORS标准的规定,所有浏览器都遵循这个逻辑:

图片(image):仅触发「Referer溯源」,无CORS校验

图片属于**「无副作用的被动嵌入资源」,浏览器加载时不会触发CORS预请求(OPTIONS)**,仅会在请求头中携带Referer(告诉服务端资源是从哪个页面发起的),不会携带OriginOrigin是CORS的核心标识,仅在强跨域校验时出现)。

  • 适用规则:仅受Referer防盗链限制;
  • 请求头特征:只有Referer: http://localhost:5173/,无Origin

视频(video/audio):触发「强CORS校验」,同时带 Origin + Referer

视频/音频属于**「可跨域读取数据的主动资源」(比如前端可通过video标签获取视频的宽高、时长等数据,甚至做跨域视频流处理),浏览器加载时会判定为「需要CORS授权的跨域请求」**,核心行为:

  • 先触发CORS预请求(OPTIONS请求):先向CDN/源站发一个OPTIONS请求,携带Origin: http://localhost:5173,询问服务端「是否允许这个源的跨域访问」;
  • 主请求同时带Origin+Referer:即使预请求通过,后续的视频GET请求也会同时携带Origin(跨域源标识)和Referer(页面溯源)
  • 适用规则:既受Referer防盗链限制,又受CORS跨域配置限制(缺一不可)。

为什么视频会 403?

当前的CDN/源站只配置了「Referer防盗链白名单」(允许localhost的Referer),但完全没有配置「CORS跨域授权」

  1. 图片请求:只有Referer,匹配防盗链白名单,CDN直接放行,正常访问;
  2. 视频请求:携带Origin,CDN/源站因无CORS配置,会判定为「未授权的跨域请求」,直接返回403(部分CDN/源站对未授权的Origin会拦截,部分会在OPTIONS预请求阶段就返回403)。

Origin 和 Referer 的核心区别

很多人会混淆这两个头,这是浏览器发送的完全不同的两个标识,作用和触发场景天差地别,也是解决问题的关键:

特征Origin头Referer头
核心作用标识跨域请求的源域名(CORS专用),用于服务端授权跨域标识请求的发起页面URL,用于服务端溯源/防盗链
携带内容仅包含「协议+域名+端口」,无路径,如http://localhost:5173包含「协议+域名+端口+路径」,如http://localhost:5173/page/index.html
触发场景仅在CORS跨域请求中携带(视频/音频/Fetch/AJAX/POST)几乎所有非直接地址栏访问的请求都携带(图片/视频/脚本/链接跳转)
是否可空跨域请求中必须非空,否则浏览器会拦截请求地址栏直接访问时为空,页面内加载时非空

实战演示:请求头对比

通过 Chrome DevTools 可以清晰看到差异:

图片请求 (img 标签)

<img src="https://cdn.xxxx.com/images/avatar.png" />

请求头:

GET /images/avatar.png HTTP/1.1
Host: cdn.xxxx.com
Referer: http://localhost:5173/
Accept: image/webp,image/apng,image/*,*/*;q=0.8

视频请求 (video 标签)

<video src="https://cdn.xxxx.com/videos/demo.mp4" controls></video>

预检请求 (OPTIONS):

OPTIONS /videos/demo.mp4 HTTP/1.1
Host: cdn.xxxx.com
Origin: http://localhost:5173
Access-Control-Request-Method: GET

主请求 (GET):

GET /videos/demo.mp4 HTTP/1.1
Host: cdn.xxxx.com
Origin: http://localhost:5173
Referer: http://localhost:5173/

解决方案

解决视频403的核心是:在CDN控制台为加速域名配置CORS规则,允许所有域名的跨域访问(CDN配置CORS后,源站无需再配,CDN会直接返回CORS授权头,效率更高)。

配置示例

CORS 响应头配置:

Access-Control-Allow-Origin: *

总结

通过这次深入分析,我们弄清了几个关键点:

  1. 浏览器对不同资源类型的跨域处理机制不同

    • 图片(img):简单跨域资源,仅发送 Referer,不触发 CORS 检查
    • 视频(video):需要 CORS 授权的资源,会发送 Origin 头并触发预检请求
  2. Origin 和 Referer 的本质区别

    • Origin:CORS 专用,标识跨域请求的源,格式为 协议://域名:端口
    • Referer:通用溯源头,标识请求来源页面,包含完整路径
  3. 403 问题的根源

    • CDN 仅配置了 Referer 防盗链,未配置 CORS
    • 图片请求通过 Referer 验证即可访问
    • 视频请求因缺少 CORS 响应头被浏览器或 CDN 拦截
  4. 解决方案:CDN 同时配置「Referer 防盗链」+ 「CORS 跨域授权」

扩展思考

这个问题揭示了前端开发中一个容易被忽视的细节:不同的 HTML 标签对同一资源的请求方式可能完全不同。类似的差异还存在于:

  • <script> vs fetch() 请求 JS 文件
  • <link> vs @import 加载 CSS
  • <iframe> vs fetch() 加载 HTML

理解这些底层机制,不仅能帮我们解决当下的问题,更能让我们在架构设计时就避开这些坑。

参考资料