upgrade-insecure-requests:把 http:// 请求在发出前改成 https
upgrade-insecure-requests 是一条 CSP 指令,浏览器在发出请求前就把 http:// 网址改写成 https://。先盘点不安全网址,再用报告模式验证,最后才强制;它替代不了 HSTS。

upgrade-insecure-requests 是一条 Content-Security-Policy 指令,它让浏览器在发出请求之前,把 http:// 网址改写成 https://。加一行响应头,页面里所有 http:// 子资源都会改走 https://。这是改写,不是修复:如果安全的网址没有响应,请求就直接失败,不会退回 HTTP。它也替代不了 HSTS,因为指向其他站点的跳转链接不在这条指令的处理范围里。
upgrade-insecure-requests 改了什么
它动手的时间比混合内容拦截更早。W3C 规范的原话是:在抓取之前(before fetching them)就把“先验不安全”的资源请求升级为安全传输,而且这次改写发生在混合内容检查与 CSP 检查之前,所以被升级的请求不会再被报成混合内容(Upgrade Insecure Requests,W3C Candidate Recommendation,2015-10-08,2026-11-03 访问)。MDN 的描述一致,并把这项能力标为自 2018 年 4 月起在主流浏览器广泛可用(MDN,2026-11-03 访问)。
时间点就是全部价值。浏览器根本没有发出那条不安全的请求,混合内容拦截也就没有东西可拦。
| 请求类型 | 会升级吗 | HTTPS 不可用时 |
|---|---|---|
| 同源图片,http:// | 会 | 图片失败,不重试 HTTP |
| 第三方脚本,http:// | 会 | 脚本失败,不重试 HTTP |
| 同源跳转链接 | 会 | 页面打不开,无回退 |
| 跳往其他站点,http:// | 不会 | 浏览器仍走 HTTP |
| 只有 HTTP 的资源 | 会 | 请求直接失败 |
第四行最容易被忽略。同源跳转会被升级,跳到另一个主机名的导航不会被升级(同一份规范第 1.2.2 节,2026-11-03 访问)。所以这条指令不能代替 HSTS。
怎么加这条指令
一行响应头就够了。把它加在所有可能包含不安全网址的 HTML 响应上。
Content-Security-Policy: upgrade-insecure-requests
如果托管平台不允许改响应头,可以退回 meta 写法。它只覆盖携带这条 meta 的那个文档,管不到别的页面。
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
不要同时再写 block-all-mixed-content。MDN 已把那条指令标为废弃;W3C 规范说 upgrade-insecure-requests 会先被计算,两条同时存在时 block-all-mixed-content 实际上什么也不做(MDN,2026-11-03 访问)。二选一,不要叠。
先找出不安全的网址,再强制
先数一遍,再决定要不要开。下面两条命令一分钟能跑完,给你一份可以核对、可以争论的清单。它们找不全:由 JavaScript 拼出来的网址、写在 CSS 里的网址,第二条命令都看不见。
# 1. 这个页面已经在发这条指令了吗?
curl -sI https://example.com | grep -i '^content-security-policy'
# 2. 还有哪些资源网址是 http://?
curl -s https://example.com \
| grep -oE '(src|href)="http://[^"]+' \
| sort -u
第二条要跑在流量最大的几个模板上,不要只跑首页。结账页、文章页和落地页常常挂着不同的第三方组件。如果改完还在报混合内容,排查路径写在mixed content 怎么修里。
正式强制之前,先用报告模式跑一轮。浏览器只发违规报告,不改写任何网址,这样你能拿真实报告和源码扫描的结果对一遍。
Content-Security-Policy-Report-Only: upgrade-insecure-requests; report-uri /csp-reports
report-uri 是比较旧的报告机制,report-to 是更新的端点配置,两者并不是在每个托管环境里都能互换。我们这次没有测各家 CDN 的报告投递,所以先确认你的端点真的收到了报告,别把“报告为空”当成“没有问题”。
它管不到的三件事
三条限制比语法重要。
- 跳到第三方站点的链接。 指向另一个主机名的 http:// 链接不会被升级。用户仍然从你的页面走 HTTP 离开,这条指令拦不住。
- 没有 HTTPS 的资源。 没有回退。升级后的网址在 HTTPS 上不响应,请求就失败,页面少一块。
- HSTS。 它不替代
Strict-Transport-Security。HSTS 管未来访问和首次导航,这条指令管当前页面发出的请求。
规范还单独处理了 WebSocket:指令生效时,不安全的 ws:// 连接会被升级成 wss://(同一份规范第 5 节,2026-11-03 访问)。我们没有拿真实 WebSocket 端点跑过,所以这一条按“规范这么写”记录,不按“我们测过”记录。
还有一个爬虫问题,我们没有答案。我们没有测过 Googlebot 或任何 AI 爬虫是否遵守这条指令。按当前浏览器的渲染方式推,它应该会吃到改写,但每个爬虫都没有实测数据,我们不把猜测写成结论。
不把页面搞坏的迁移顺序
这是我会在一个积了多年 http:// 网址的站上用的顺序。
- 先盘点模板。 在上面那两条命令跑真正重要的页面,不只首页,把输出存成文件。
- 先修自己能控的资源。 把同源图片、字体和脚本搬到 HTTPS。这些失败看得见,一次部署就能修。
- 逐个查第三方。 向供应商要 HTTPS 地址。对方没有,就在强制之前换掉或删掉那个资源。
- 报告模式跑一轮抓取周期。 把报告和盘点结果对一遍。报告里有、清单里没有的网址,就是源码扫描漏掉的那一批。
- 强制,然后复验。 换成强制头,打开网络面板刷新,确认没有请求还在走 http://。HSTS 单独决策,不要混在这一步里。
交付物是那份盘点表加报告对照,不是那一行响应头。响应头十秒就能加,盘点才是活。
三种会静默失败的情况
三种都在第一次加载时悄悄坏掉,其中两种看起来像 CDN 的问题。
- 第三方还没支持 HTTPS 就强制。 请求被改写,对方 443 端口不响应,资源消失,不会退回 HTTP 重试。
- 以为它管顶层链接。 指向合作方站点的 http:// 链接还是把访客送过 HTTP。那个位置归 HSTS 管。
- 两条 CSP 指令一起写。
block-all-mixed-content已废弃,升级指令在场时它什么也不做。两行看起来更安全,一行才是准确的配置。
什么时候不该用
如果页面还依赖一个只有 HTTP 的第三方脚本,强制会在第一次加载时打断它。如果要防的是首次访问被降级攻击,工具是 HSTS,配套要决定 max-age 和 preload。如果只有几条不安全网址,直接改掉就行;这条指令是给这周改不完的长尾用的。
一次升级失败会损失多少流量,我们给不出数字。那取决于坏的是哪个资源、页面少了它还能做什么。量页面,别量响应头。
常见问题
它和 HSTS 是一回事吗?
不是。HSTS 让浏览器以后访问某个主机时直接走 HTTPS;upgrade-insecure-requests 改写当前页面发出的不安全请求。W3C 规范把两者分开写,并明说这条指令不替代 HSTS(2026-11-03 访问)。
它能消掉混合内容警告吗?
大部分混合内容请求会在发出前被改写,所以不会再以不安全的方式出现。它修不了一个根本没有 HTTPS 版本的资源,那种请求会直接失败。
写在 meta 里能用吗?
能用,但只覆盖带这条 meta 的那个文档。响应头覆盖你配置的每一个 HTML 响应;meta 只管自己那一页。
Upgrade-Insecure-Requests 请求头是什么?
那是另一个头。浏览器发 Upgrade-Insecure-Requests: 1,告诉服务器自己支持升级;服务器可以据此对不安全请求回 307 跳转。它是能力探测,不是这条强制指令。
套 CDN 还能用吗?
能,前提是 CDN 把响应头透传过去。部署后用 curl -sI 查一次响应。我们这次没有测每一家 CDN 的头处理,自己的边缘节点要自己确认。
Googlebot 认这条指令吗?
我们没测。上线前用自己的日志或一次带渲染的抓取确认,别拿别人的说法当结论。
下一步
页面只剩 HTTPS 之后,下一个问题是爬虫拿到的 HTML 跟你看到的是不是同一份。查一次 AI 爬虫实际收到什么;要把请求和渲染结果并排看,用 QueryWin 的页面视图。
本文属于 QueryWin 实操手册 · 第 2 阶


