点击的链接,往往不是最终打开的页面。中间可能经过 HTTPS 升级、主机名变更、跟踪服务、短链接服务,以及一条添加末尾斜杠的 CMS 规则,每一步都是浏览器在您不知情的情况下单独发出的一次请求。

本文介绍如何用 TrueURL、curl 和浏览器开发者工具(DevTools)查看这些步骤,重定向链的各个部分分别代表什么,以及如何修复最常见的问题。

什么是重定向链

当服务器返回 3xx 状态码,并在 Location 响应头中给出另一个 URL 时,就发生了重定向。客户端(浏览器或爬虫)随后请求这个 URL,并不断重复这一过程,直到收到一个不是重定向的响应为止。

每一次请求及其响应构成一跳(hop)。从第一个 URL 到最终响应的整个序列,就是重定向链:

#  URL                              Status  Location
1  http://example.com/Shoes         301     https://example.com/Shoes
2  https://example.com/Shoes        301     https://www.example.com/Shoes
3  https://www.example.com/Shoes    302     /shoes/
4  https://www.example.com/shoes/   200

为了打开一个页面,这里经过了 3 次重定向、发出了 4 个请求。第 3 跳的 Location 是相对地址:按照 RFC 9110 的规定,客户端会以刚刚请求的 URL 为基准来解析它,因此它实际指向 https://www.example.com/shoes/。理想情况下,上面每一个地址都应该只用一跳就到达最终 URL。

页面也可以在返回 200 OK 之后,通过 <meta http-equiv="refresh"> 标签或 JavaScript 进行重定向。这类客户端重定向同样属于重定向链,但 curl 等只读取 HTTP 响应头的工具会停在这个页面上。

为什么要检测重定向

SEO:规范化信号与抓取预算

搜索引擎会把重定向理解为一种声明:应该将哪个 URL 编入索引。Google 会将永久重定向(301 和 308)视为强信号,表明目标 URL 应当成为规范 URL;临时重定向(302、303 和 307)则只是弱信号。因此,一个已经永久迁移、却使用 302 重定向的页面,可能会在搜索结果中继续显示旧 URL。

链的长度同样重要。Google 抓取工具(Googlebot)最多跟随 10 跳重定向;如果到那时仍未获取到内容,Search Console 就会报告重定向错误。Google 的抓取预算(crawl budget)指南也建议避免过长的重定向链,并指出它们会对抓取产生负面影响。

页面速度

在最后一次重定向得到响应之前,最终页面无法开始加载。每一跳都要花费一次网络往返;如果跳到新的主机,还需要进行 DNS 查询、建立新连接,对于 HTTPS 还要完成 TLS 握手。在移动网络下,三四次重定向就可能让真实页面的第一个字节推迟数百毫秒才到达。重定向延迟检测工具可以显示每一跳的耗时。

短链接和来路不明链接的安全性

短链接(短网址)和邮件中的许多跟踪链接都会隐藏真实的目标地址。钓鱼攻击还会利用知名域名上的开放重定向,因此一个从可信网站开始的链接,最终可能通向完全不同的地方。在点击之前,短链接还原工具就能显示沿途经过的每一个域名,以及是否有某一跳从 HTTPS 降级为普通 HTTP。

联盟推广链接与跟踪链接

营销链接在到达落地页之前,往往要经过多个服务,每个服务都必须把查询字符串原样传递下去,否则 UTM 参数、点击 ID 和联盟推广标识就会在不知不觉中丢失。查看最终 URL,就能知道这些参数是否保留了下来,以及链接是否仍然通向预期的页面。

网站迁移、HTTPS 与规范主机名

网站改版、更换域名或切换到 HTTPS 之后,每个旧 URL 都应该通过一次永久重定向到达对应的新 URL。网站的 4 种基本形式(http:// 和 https://,各自带或不带 www)最终都应该落到同一个规范地址上。这些规则失效时往往悄无声息:一条新的 CDN 规则、一次插件更新或一次服务器迁移,都可能在没人察觉的情况下多出一跳,甚至造成循环。

如何用 TrueURL 检测重定向

TrueURL 的每一次检测都在 Cloudflare 边缘网络上运行,因此无需在浏览器中打开,就能检测您不信任的链接。首页的 URL 重定向检测工具用于检测单个 URL;重定向链检测和其他专用工具使用的是同一个检测引擎。

第 1 步:输入 URL

粘贴 URL 并开始检测。如果没有写协议,默认使用 https://;要测试普通 HTTP,请输入 http://。

第 2 步:按需调整高级设置

默认情况下,检测工具会发送 GET 请求,使用较新版本桌面版 Chrome 的 User-Agent(用户代理),不带 Cookie,最多跟踪 20 次重定向。在高级设置中可以更改这些选项:

  • HTTP 方法:GET、HEAD 或 POST。HEAD 请求更轻量,但有些服务器对它的响应与 GET 不同,而且没有响应体就无法检测客户端重定向。POST 会发送您填写的请求体,适用于表单处理程序和 API。后续各跳遵循浏览器规则:POST 之后,遇到 301 或 302 会改用 GET 继续,遇到 303 则始终改用 GET,而 307 和 308 会保留原方法和请求体。
  • 最大跳数:要跟踪的重定向次数,可设为 1~50。默认值 20 与 Fetch 标准以及 Chrome 和 Firefox 的上限相同。设为 10,即可查看重定向链是否在 Googlebot 的限制之内。
  • 自定义 User-Agent:留空则使用桌面版 Chrome。预设包括 iPhone 上的 Safari、Android 上的 Chrome、Googlebot(智能手机版和桌面版)、Bingbot、Facebook 和 X 的链接预览爬虫,以及 curl。
  • 自定义请求头:在每一跳都会发送的额外请求头,例如用 Accept-Language: fr-FR 触发按语言进行的重定向。
  • Cookie:输入 name=value; other=value,即可复现已登录、已同意 Cookie 使用或特定地区的访问状态。与浏览器一样,重定向链中设置的 Cookie 会保留到后续各跳。
  • 客户端重定向:选择跟踪 meta refresh(HTML 页面自动刷新)标签和简单的 JavaScript 重定向,还是只报告、不跟踪。
  • 忽略 SSL 错误:Cloudflare 边缘网络始终会验证证书,因此这个选项无法跳过有问题的证书。TLS 错误会在出错的那一跳上报告。

第 3 步:解读检测结果

检测结果最上方是最终 URL 及其状态码。下方的重定向链每跳一行,包括:

  • 请求的 URL 和使用的 HTTP 方法;
  • 状态码和原因短语(HTTP 状态码大全逐一解释了每个状态码);
  • 响应时间,即从发出请求到收到响应头所用的时间,包括 DNS 查询和建立连接的时间;
  • 它所指向的 Location;
  • 响应头,以及该跳设置的 Cookie 的名称。

每次重定向都会标注其发生方式:HTTP 状态码、meta refresh(附带以秒为单位的延迟)或 JavaScript。已发现但未跟踪的客户端重定向也会一并报告。同样重要的是检测以何种方式结束:

检测结论 含义
最终响应 重定向链到达了一个不是重定向的响应,例如 200 OK 或 404 Not Found。
重定向循环 下一个请求将与之前的某个请求完全相同:URL、方法和 Cookie 都一样。结果会显示循环在哪一跳闭合。
达到最大跳数 到达上限时,重定向链仍在继续重定向。下一个目标地址会显示出来,但不会被请求。
错误 某一跳失败:DNS、连接、TLS 错误或超时,或者重定向目标不是有效的或允许访问的 URL。

警告会提示以下情况:链中存在临时重定向、从 HTTPS 降级到 HTTP、重定向超过 3 次、最终 URL 位于其他域名、存在客户端重定向,以及 HEAD 请求无法读取页面内容。

其中有一种警告需要特别留意。有些网站会向自动化流量或来自数据中心的流量展示人机验证(质询)页面,例如 Cloudflare 的“Just a moment...”页面。TrueURL 会标出看起来像这类页面的响应,因为此时检测到达的是网站的防护层,而不是目标页面。真实访客最终到达的可能是别的地方。

如何在命令行中检测重定向

macOS、Windows 10 和 11 以及大多数 Linux 发行版都预装了 curl。它会如实显示服务器发送的内容,不受浏览器缓存的影响。以下示例使用 Unix shell;在 Windows PowerShell 5.1 中,请输入 curl.exe,因为在那里 curl 是 Invoke-WebRequest 的别名,并用 NUL 代替 /dev/null。

查看单独一跳

Bash
curl -I https://example.com/old-page

-I 会发送 HEAD 请求并打印响应头,包括状态行和 Location(如果有)。除非明确要求,curl 不会跟随重定向。由于有些服务器对 HEAD 的处理方式不同,如果结果看起来不对劲,请改用 GET 再检测一次;-o /dev/null 会丢弃响应体,-D - 会打印响应头:

Bash
curl -sS -o /dev/null -D - https://example.com/old-page

跟踪整条重定向链

-L 会跟随重定向;搭配 -I 或 -D - 使用时,curl 会打印每一跳的响应头。再用 grep 过滤一下,就能得到简洁的视图:

Bash
curl -sIL http://example.com/Shoes | grep -iE '^(HTTP/|location:)'
HTTP/1.1 301 Moved Permanently
Location: https://example.com/Shoes
HTTP/2 301
location: https://www.example.com/Shoes
HTTP/2 302
location: /shoes/
HTTP/2 200

curl 默认最多跟随 50 次重定向;--max-redirs 10 可以套用 Googlebot 的限制。

只打印最终 URL

-w(write-out)选项会在传输完成后打印指定的信息,让 curl 变成一个小巧的短链接还原工具:

Bash
curl -sSL -o /dev/null -w '%{http_code} %{num_redirects} %{url_effective}\n' https://example.com/go

%{url_effective} 是最后获取的 URL,%{num_redirects} 是跟随的重定向次数,%{http_code} 是最终状态码。%{time_redirect} 报告在发出最终请求之前花在重定向上的秒数。不加 -L 时,%{redirect_url} 会显示第一次重定向将指向哪里。

测试 POST 请求

-d 会发送请求体,并把请求变为 POST。跟随重定向时,curl 的行为与浏览器一致:遇到 301、302 或 303 后改用 GET,遇到 307 或 308 则重新发送 POST 及其请求体。

Bash
curl -sSL -o /dev/null -D - -d 'email=test%40example.com' https://example.com/subscribe

不要把 -X POST 和 -L 一起使用。-X 会强制每个请求都使用指定的方法,因此在 301、302 或 303 之后,浏览器本会改用 GET,curl 却继续发送 POST,这样测试的就是一条任何真实客户端都不会产生的重定向链。

Bash
# 智能手机 User-Agent
curl -sIL -A 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1' https://example.com/

# 额外的请求头
curl -sIL -H 'Accept-Language: de-DE,de;q=0.9' https://example.com/

# 发送 Cookie,并保留重定向链中设置的 Cookie
curl -sSL -o /dev/null -D - -b 'consent=yes' -c cookies.txt https://example.com/

-A 用于设置 User-Agent,-H 用于添加请求头,-b 用于发送 Cookie。-c 会把收到的 Cookie 保存到文件中,并启用 curl 的 Cookie 引擎,这样某一跳设置的 Cookie 会在下一跳中发送出去。

curl 不会运行 JavaScript,也不会处理 meta refresh 标签。如果 curl 拿到的最后一个响应是 200 OK 的 HTML 页面,而浏览器最终却到了别的地方,说明重定向发生在客户端。

如何用浏览器开发者工具检测重定向

开发者工具展示的是您自己的浏览器实际看到的重定向链,会受到您的 Cookie、扩展程序和所在位置的影响:

  1. 打开开发者工具(按 F12,Mac 上按 Cmd+Option+I),选择网络(Network)标签页。
  2. 在 Chrome 和 Edge 中勾选保留日志(Preserve log),在 Firefox 中则打开网络设置菜单里的持续记录日志(Persist Logs)。否则每次加载页面时列表都会被清空,客户端重定向也会随之从视图中消失。
  3. 勾选停用缓存(Disable cache),以免缓存的重定向掩盖服务器当前实际发送的内容。
  4. 在地址栏中输入 URL。

每一跳都单独显示为一行,并带有相应的 3xx 状态码;选中该行并打开标头(Headers)面板,即可看到 location 响应头。在 Chrome 中,如果大小(Size)列显示“(磁盘缓存)”或“(内存缓存)”(英文界面为“(disk cache)”或“(memory cache)”),说明该重定向来自缓存,而不是服务器。

Chrome 有时会列出一个从 http:// 到 https:// 的 307 Internal Redirect。服务器从未发送过这个响应:是浏览器自己升级了请求,通常是因为它已为该网站存储了 HSTS(HTTP 严格传输安全)策略。要查看服务器如何处理普通 HTTP 请求,请使用 curl 或 TrueURL。

常见的重定向问题及修复方法

超过一跳的重定向链

重定向链是一层层叠加出来的:早年迁移时留下的规则指向某个 URL,而这个 URL 在后来的迁移中又被重定向了一次。应让每条规则都直接指向最终目标地址,并更新内部链接、canonical 标签(规范标签)、hreflang 注释和站点地图,确保自己的网站不会触发任何重定向。批量重定向检测工具可以找出哪些旧 URL 仍然需要不止一跳。

重定向循环

Chrome 遇到循环时会提示“将您重定向的次数过多”(ERR_TOO_MANY_REDIRECTS);Firefox 则显示“The page isn't redirecting properly”。常见原因包括:

  • 代理或 CDN 背后的 HTTPS:源服务器把 HTTP 重定向到 HTTPS,但代理通过普通 HTTP 连接源服务器,于是源服务器永远看不到 HTTPS 请求,只能无休止地重定向下去。在 Cloudflare 上,这是使用 Flexible SSL/TLS 模式的典型后果;请改用 Full (strict) 模式,或者让源服务器检查 X-Forwarded-Proto。
  • 两层规则相互冲突:例如 CDN 规则去掉 www,而服务器又把它加上;或者框架添加末尾斜杠,而 CDN 又把它去掉。
  • 依赖 Cookie 的重定向:登录页或 Cookie 同意页把访客送回原来的 URL,但由于 Cookie 没有保存下来,原 URL 又把访客重定向到登录页。

重定向循环检测工具会显示循环在哪一跳闭合。找到之后,让每条规则只由一层负责。

同一条链中混用 301 和 302

一条先 301、再 302、最后 200 的重定向链,相当于在永久迁移的中间插入了一个临时步骤。这通常源于默认设置:Express 的 res.redirect() 和 PHP 的 header('Location: ...') 在未指定状态码时都会发送 302。应在每一跳都使用永久重定向状态码,并用 301 重定向检测工具加以确认。我们的 HTTP 重定向状态码详解一文介绍了每种状态码分别适用于什么场景。

从 HTTP 到 HTTPS 再到 www 的两跳重定向

一种非常常见的链是 http://example.com → https://example.com → https://www.example.com:本来一跳就够,却用了两跳。应把每个非规范形式直接重定向到最终的 HTTPS URL,然后用 HTTPS 重定向检测工具测试全部 4 种形式。

有一种例外是有意为之的。如果规范主机名是 www,而您又要把域名加入 HSTS 预加载列表,hstspreload.org 要求 http://example.com 先重定向到 https://example.com,以便浏览器为裸域名记录 HSTS 策略。

末尾斜杠不一致

/pricing 和 /pricing/ 是两个不同的 URL。如果两者都返回 200 OK,就会产生重复内容;如果两层规则分别把它们重定向到对方,就会形成循环。选定其中一种形式,用一次 301 把另一种形式重定向过来,并在所有链接中保持一致。URL 末尾斜杠检测工具可以同时测试这两种形式。

仅针对移动端的重定向

独立的移动版网站、应用安装提示和设备检测,有时会把手机用户送到别处,而且往往是移动版首页,而不是对应的页面。在移动设备优先索引机制下,Google 主要使用智能手机抓取工具进行抓取,因此对于编入索引来说,移动端的重定向链最为关键。可以用移动端与桌面端重定向对比工具比较两者。

站点地图中的重定向

站点地图应当列出您希望出现在搜索结果中的规范 URL,而这些 URL 返回的都是 200 OK。会重定向的条目既浪费抓取请求,又会发出相互矛盾的规范化信号。每次迁移之后,都应运行站点地图重定向检测,并把每个会重定向的条目替换为它的最终 URL。

JavaScript 重定向与 meta refresh 重定向

Google 会将即时的 meta refresh 视为永久重定向,将有延迟的视为临时重定向。至于 JavaScript 重定向,Google 只有在渲染页面之后才能发现,而渲染发生在抓取之后,并且可能失败。其他许多爬虫(包括链接预览爬虫)和命令行工具根本不运行 JavaScript,有些甚至还会忽略 meta refresh。只要能控制服务器,就应使用服务器端重定向;客户端重定向则可以用 Meta Refresh 重定向检测工具找出来。

重定向检查清单

在网站迁移、更改 CDN 配置之后,或者在推广活动上线之前,请对照以下清单逐项检查:

  1. 每个旧 URL 都只用一跳就到达最终目标地址。
  2. 永久迁移在每一跳都使用 301 或 308。
  3. 协议和主机名的全部 4 种组合最终都落在规范的 HTTPS URL 上。
  4. 没有任何一跳从 HTTPS 降级到 HTTP。
  5. 查询字符串(包括 UTM 参数和联盟推广 ID)在经过整条链后依然完整保留。
  6. 每个 URL 只使用一种末尾斜杠形式,另一种形式会重定向到它。
  7. 桌面端、智能手机和 Googlebot 的请求最终都到达相互对应的页面。
  8. 尽可能用服务器端重定向取代 meta refresh 和 JavaScript 重定向。
  9. 内部链接、canonical 标签、hreflang 和站点地图都指向最终 URL。
  10. 已删除且没有替代页面的页面返回 404 或 410,而不是重定向到首页。
  11. 网站迁移时设置的重定向要长期保留;Google 建议至少保留一年。