☰
JavaScript.info 跨域请求探秘:为什么有了 Referer 还需要 Origin 头
2026/10/8 13:38:33 网站建设 项目流程
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

跨域(Cross-Origin)请求是浏览器安全模型的基石,而Origin与Referer是两个极易混淆的 HTTP 请求头:Referer携带完整页面 URL,信息量显然更大,那为什么浏览器还要额外发明并强制保证Origin?本篇以现代 JavaScript 教程中「Fetch: Cross-Origin Requests」的配套问答为骨架,结合仓库中 fetch 基础章节 与 fetch 选项章节 的源码级文档,系统梳理Referer的不可靠性、Origin的设计初衷,以及浏览器作为可信中介在 CORS 中如何利用Origin完成跨域安全校验。读完你将彻底理解两个头的职责边界,并掌握用referrer/referrerPolicy控制Referer的实战方法。

问题背景:请求头里同时出现的两个「来源」

当从http://javascript.info/some/url页面发起对http://google.com的fetch请求时,浏览器发送的 HTTP 请求头大致长这样:

Accept: */* Accept-Charset: utf-8 Accept-Encoding: gzip,deflate,sdch Connection: keep-alive Host: google.com Origin: http://javascript.info Referer: http://javascript.info/some/url

如你所见,Referer和Origin同时出现。这里自然引出两个问题:

  1. 既然Referer包含了更完整的信息(完整 URL 带路径),为什么还需要Origin?
  2. 是否存在Referer或Origin缺失、甚至不正确的可能?

核心解答:因为 Referer 不可靠,所以需要 Origin

答案的第一层很简单:我们需要Origin,因为Referer有时会缺席。原文档给出的结论可以用四个事实支撑:

  1. HTTPS→HTTP 场景下Referer直接消失:当从 HTTPS 页面(更安全的协议)fetch一个 HTTP 页面(较不安全的协议)时,浏览器会省略Referer。这是「从更安全的环境访问较不安全环境」时的隐私保护策略,而Origin依然照常发送。
  2. Content Security Policy(内容安全策略)可能禁止发送Referer:站点可以通过 CSP 指令禁止请求携带Referer头,此时它自然缺席。
  3. fetch本身提供了关闭甚至篡改Referer的选项:如后文所述,referrer: ""可让fetch完全不发送Referer,referrer选项甚至允许在同源范围内修改它的值。
  4. 按规范,Referer本来就是可选 HTTP 头:RFC 规范中Referer是 optional 的,任何实现都可以选择不发送。

正因为Referer不可靠,Origin才被发明出来——对于跨域请求,浏览器保证发送正确的Origin。换句话说:Origin是浏览器层面的强保证,Referer只是「通常存在、但别指望它」的辅助信息。

纵深一:Origin 与 Referer 的本质区别

对比两个头可以更清楚地看到设计分工:

维度OriginReferer
携带内容仅 origin(协议 + 域名 + 端口),不含路径完整页面 URL(含路径与查询参数)
信息量少(更克制)多(更暴露)
规范地位跨域请求由浏览器强制附加可选头,可能被省略
浏览器保证跨域请求保证正确不保证(可能缺失、可能被策略禁止)
可否被脚本修改禁止(forbidden header)可通过referrer/referrerPolicy影响

Origin的「少即是多」并非缺陷:它只暴露「来自哪个站点」这一最小必要信息,避免把内部路径泄漏给第三方服务器。而信息量更大的Referer因为各种原因不可靠,无法承担安全校验的重任——服务器不能基于一个可能缺失、可能被篡改的头做信任决策。

纵深二:浏览器是 CORS 的可信中介

要理解Origin的「保证」从何而来,需要回到 CORS 主章节 的机制描述。只要请求是跨域的,浏览器总是为它附加Origin头,其值恰好是发起页面自身的 origin(domain/protocol/port),不含路径:

GET /request Host: anywhere.com Origin: https://javascript.info ...

在跨域请求的整个生命周期中,浏览器扮演着「可信中介」的双重角色:

  1. 发送侧保证:确保跨域请求带上正确的Origin头,脚本无法伪造;
  2. 接收侧检查:检查响应中是否存在匹配的Access-Control-Allow-Origin头(允许的具体 origin 或*),若存在则把响应交给 JavaScript,否则报错。

正因为浏览器是唯一能「保证 Origin 正确」的一方,服务器端 CORS 校验才得以建立在Origin之上。这一完整交互流程可以直观地用主章节的示意图说明:

纵深三:为什么脚本无法伪造 Origin

另一个支撑Origin可靠性的细节来自 fetch 请求头章节:Fetch 规范定义了一批forbidden HTTP headers(禁止请求头),脚本无法通过headers选项设置,其中包括:

  • Accept-Charset、Accept-Encoding
  • Access-Control-Request-Headers、Access-Control-Request-Method
  • Connection、Content-Length、Cookie、Cookie2、Date、DNT
  • Expect、Host、Keep-Alive
  • Origin
  • Referer
  • TE、Trailer、Transfer-Encoding、Upgrade、Via
  • Proxy-*、Sec-*等

注意Origin和Referer都在禁止列表中:这些头「确保正确且安全的 HTTP」,因此由浏览器独占控制。这从实现层面解释了为什么浏览器能「保证」Origin正确——脚本根本没有途径覆盖它。而Referer虽然同样禁止脚本直接设置,却可以缺失或被 CSP 拦截,这正是它与Origin可靠性差异的根源。

实战:用 referrer / referrerPolicy 控制 Referer

理解了「为什么需要 Origin」,再看 fetch-api 的 referrer 章节 中管理Referer的两个选项,思路就清晰了——既然Referer本就不可靠,网站完全可以主动决定它的行为。

referrer选项:精确控制单个请求的 Referer

  • 设为空字符串"":完全不发送Referer头:
fetch('/page', { referrer: "" // 不发送 Referer 头 });
  • 设为当前 origin 内的任意 URL:替换Referer的值(注意:仅限当前 origin 内,跨 origin 无法设置):
fetch('/page', { // 假设当前页面位于 https://javascript.info // 可以设置任意 Referer,但仅限当前 origin 内 referrer: "https://javascript.info/anotherpage" });

referrerPolicy选项:按请求类型设定通用规则

与精确设置单个值不同,referrerPolicy告诉浏览器对不同类型请求采用何种策略。请求分为三类:同源请求、跨源请求、HTTPS→HTTP(从安全协议到不安全协议)请求。可用值与效果如下:

值同源请求跨源请求HTTPS→HTTP
"no-referrer"不发送不发送不发送
"no-referrer-when-downgrade"完整完整不发送
"origin"仅 origin仅 origin仅 origin
"origin-when-cross-origin"完整仅 origin仅 origin
"same-origin"完整不发送不发送
"strict-origin"仅 origin仅 origin不发送
"strict-origin-when-cross-origin"(默认)完整仅 origin不发送
"unsafe-url"完整完整完整

典型场景:某个后台管理区存在不希望外部站点得知的 URL 结构,默认策略下跨域请求会把完整 URL 放进Referer(如Referer: https://javascript.info/admin/secret/paths)。此时可用:

fetch('https://another.com/page', { // ... referrerPolicy: "origin-when-cross-origin" // Referer 只保留 origin 部分 });

这样第三方站点只能看到https://javascript.info,看不到路径。注意该策略是全局性的——不仅作用于fetch,也可通过Referrer-PolicyHTTP 响应头为整页设置默认策略,或通过<a rel="noreferrer">逐链接控制。

总结

  • Origin的存在是为了弥补Referer的不可靠:Referer是可选头,可能因 HTTPS→HTTP 降级、CSP 策略或fetch的referrer选项而缺失,规范上也不强制其存在。
  • 跨域请求的Origin由浏览器保证正确:它只携带 origin 三要素(协议/域名/端口),且属于 forbidden header,脚本无法伪造;浏览器作为可信中介,既负责附加正确的Origin,又负责核对响应中的Access-Control-Allow-Origin决定是否放行。
  • 服务器应基于Origin而非Referer做跨域信任决策:前者是强保证,后者只是「通常存在」的弱信息。
  • 想主动管理Referer,可在fetch中使用referrer: ""移除它、referrer同源替换它,或用referrerPolicy按请求类型设定规则——这些实践均可在本仓库的 CORS 主章节、fetch 请求头章节 与 fetch-api 章节 中逐一验证。
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询