HTTP 中的重定向

URL 重定向,也称为URL 转发,是一种为页面、表单、整个网站或 Web 应用程序提供多个 URL 地址的技术。HTTP 为此操作提供了一种特殊的响应,称为 HTTP 重定向

重定向可实现众多目标

  • 网站维护或停机期间的临时重定向
  • 更改网站 URL 后,为保留现有链接/书签的永久重定向;上传文件时的进度页面等。

原理

在 HTTP 中,重定向是由服务器向请求发送特殊的重定向响应触发的。重定向响应具有以 3 开头的状态码和包含要重定向到的 URL 的 Location 标头。

当浏览器收到重定向时,它们会立即加载 Location 标头中提供的新 URL。除了额外的往返带来的少量性能损失外,用户很少会注意到重定向。

A request made from client to server. The server responds with "301:moved permanently" and the new URL for the resource. The client makes a GET request for the new URL which is returned by the server, with a 200 OK response.

重定向有多种类型,分为三类

  1. 永久重定向
  2. 临时重定向
  3. 特殊重定向

永久重定向

这些重定向旨在永久有效。它们意味着原始 URL 不应再使用,并被新 URL 替换。搜索引擎机器人、RSS 阅读器和其他爬虫会更新资源的原始 URL。

代码 文本 方法处理 典型用例
301 永久移动 GET 方法不变。其他方法可能会或可能不会更改为 GET。[1] 网站重组。
308 永久重定向 方法和正文不变。 网站重组,包含非 GET 链接/操作。

[1] 规范无意允许方法更改,但现有用户代理确实会更改其方法。308 的创建是为了消除使用非 GET 方法时行为的模糊性。

临时重定向

有时无法从其规范位置访问请求的资源,但可以从其他位置访问。在这种情况下,可以使用临时重定向。

搜索引擎机器人和其他爬虫不会记住新的临时 URL。临时重定向也用于创建、更新或删除资源时,以显示临时进度页面。

代码 文本 方法处理 典型用例
302 已找到 GET 方法不变。其他方法可能会或可能不会更改为 GET。[2] Web 页面因不可预见的原因暂时不可用。
303 查看其他 GET 方法不变。其他方法更改GET(正文丢失)。 PUTPOST 后用于重定向,这样刷新结果页面就不会重新触发操作。
307 临时重定向 方法和正文不变 Web 页面因不可预见的原因暂时不可用。当网站上存在非 GET 操作时,比 302 更好。

[2] 规范无意允许方法更改,但现有用户代理确实会更改其方法。307 的创建是为了消除使用非 GET 方法时行为的模糊性。

特殊重定向

304(未修改)将页面重定向到本地缓存的副本(已过期),而 300(多项选择)是手动重定向:浏览器以网页形式显示的正文列出了可能的重定向,用户点击其中一个进行选择。

代码 文本 典型用例
300 多项选择 不多:选项在正文中的 HTML 页面中列出。鼓励将机器可读的选项作为带有 rel=alternateLink 标头发送。
304 未修改 针对重新验证的条件请求发送。指示缓存的响应仍然有效且可以使用。

指定重定向的替代方式

HTTP 重定向不是定义重定向的唯一方式。还有另外两种方式

  1. 使用 <meta> 元素的 HTML 重定向
  2. 通过 DOM 的 JavaScript 重定向

HTML 重定向

HTTP 重定向是创建重定向的最佳方式,但有时您无法控制服务器。在这种情况下,请尝试在页面的 <head> 中使用 <meta> 元素,并将其 http-equiv 属性设置为 Refresh。显示页面时,浏览器将转到指示的 URL。

html
<head>
  <meta http-equiv="Refresh" content="0; URL=https://example.com/" />
</head>

content 属性应以一个数字开头,指示浏览器在重定向到给定 URL 之前应等待多少秒。为了符合辅助功能要求,始终将其设置为 0

显然,此方法仅适用于 HTML,不能用于图像或其他类型的内容。

JavaScript 重定向

JavaScript 中的重定向通过将 URL 字符串设置为 window.location 属性来执行,从而加载新页面

js
window.location = "https://example.com/";

与 HTML 重定向一样,这不能对所有资源都有效,而且显然,这只适用于执行 JavaScript 的客户端。另一方面,有更多可能性:例如,您可以仅在满足某些条件时触发重定向。

优先顺序

有三种触发重定向的方式,可以同时使用多种方式。但哪个先应用?

  1. HTTP 重定向总是首先执行——它们甚至在没有传输页面时就存在了。
  2. 有点令人惊讶的是,JavaScript 重定向在 HTML 重定向之前执行。这是因为 <meta> 重定向发生在页面完全加载之后,也就是所有脚本执行之后。
  3. 如果页面加载之前没有执行任何 HTTP 重定向或 JavaScript 重定向,则执行 HTML 重定向(<meta>)。
  4. 如果在页面加载后发生任何 JavaScript 重定向(例如,点击按钮时),如果页面尚未被先前的方法重定向,它将最后执行。

如果可能,请使用 HTTP 重定向,不要添加 <meta> 元素重定向。如果有人更改了 HTTP 重定向但忘记更改 HTML 重定向,重定向将不再相同,这可能导致无限循环或其他噩梦。

用例

重定向有许多用例,但由于每次重定向都会影响性能,因此应将其使用降至最低。

域名别名

理想情况下,每个资源都有一个位置,因此有一个 URL。但资源有替代名称的原因

扩大您网站的覆盖范围

一个常见的情况是,网站位于 www.example.com,但从 example.com 访问也应该有效。因此,会设置将 example.com 重定向到 www.example.com。您还可以从您的域名的常见同义词或常见拼写错误进行重定向。

迁移到新域名

例如,您的公司改名了,但您希望现有链接或书签仍然可以通过新名称找到您。

强制 HTTPS

对您网站的 http:// 版本的请求将重定向到您网站的 https:// 版本。

重构网站时,URL 会更改。即使您更新网站链接以匹配新 URL,您也无法控制外部资源使用的 URL。

您不想破坏这些链接,因为它们会带来有价值的用户并帮助您的 SEO,因此您会设置从旧 URL 到新 URL 的重定向。

注意:此技术适用于内部链接,但尽量避免内部重定向。重定向会产生显着的性能成本(因为会发生额外的 HTTP 请求)。如果您可以通过纠正内部链接来避免它,您应该修复这些链接。

对不安全请求的临时响应

不安全的请求会修改服务器的状态,用户不应无意中重新发送它们。

通常,您不希望用户重新发送 PUTPOSTDELETE 请求。如果您将此请求的结果作为响应提供,则按重新加载按钮将重新发送请求(可能在确认消息之后)。

在这种情况下,服务器可以针对包含正确信息的 URL 发回 303(查看其他)响应。如果按下重新加载按钮,只会重新显示该页面,而不会重播不安全的请求。

对长时间请求的临时响应

某些请求可能需要在服务器上花费更多时间,例如计划稍后处理的 DELETE 请求。在这种情况下,响应是 303(查看其他)重定向,该重定向链接到一个页面,指示操作已安排,并最终通知其进度或允许取消它。

在常用服务器中配置重定向

Apache

重定向可以在服务器配置文件或每个目录的 .htaccess 中设置。

mod_alias 模块具有 RedirectRedirectMatch 指令,默认情况下会设置 302 重定向

apacheconf
<VirtualHost *:443>
  ServerName example.com
  Redirect / https://www.example.com
</VirtualHost>

URL https://example.com/ 将重定向到 https://www.example.com/,其下的任何文件或目录也将重定向(https://example.com/some-page 将重定向到 https://www.example.com/some-page

RedirectMatch 作用相同,但接受正则表达式来定义受影响的 URL 集合

apacheconf
RedirectMatch ^/images/(.*)$ https://images.example.com/$1

images/ 目录中的所有文档都将重定向到不同的域。

如果您不想要临时重定向,可以使用额外的参数(要使用的 HTTP 状态码或 permanent 关键字)来设置不同的重定向

apacheconf
Redirect permanent / https://www.example.com
# …acts the same as:
Redirect 301 / https://www.example.com

mod_rewrite 模块也可以创建重定向。它更灵活,但也更复杂一些。

Nginx

在 Nginx 中,您为要重定向的内容创建一个特定的服务器块

nginx
server {
  listen 80;
  server_name example.com;
  return 301 $scheme://www.example.com$request_uri;
}

要将重定向应用于目录或仅某些页面,请使用 rewrite 指令

nginx
rewrite ^/images/(.*)$ https://images.example.com/$1 redirect;
rewrite ^/images/(.*)$ https://images.example.com/$1 permanent;

IIS

在 IIS 中,您使用 <httpRedirect> 元素来配置重定向。

重定向循环

重定向循环发生在已跟踪的重定向之后又出现额外重定向时。换句话说,存在一个永远不会结束的循环,并且永远找不到页面。

大多数情况下,这是一个服务器问题,如果服务器能够检测到它,它会返回 500 Internal Server Error。如果您在修改服务器配置后不久遇到此类错误,则很可能是重定向循环。

有时,服务器不会检测到它:重定向循环可能跨越多个服务器,每个服务器都没有完整的视图。在这种情况下,浏览器会检测到它并显示错误消息。Firefox 显示

Firefox 检测到服务器以一种永远不会终止的方式重定向此地址的请求。

……而 Chrome 显示

此网页存在重定向循环

在这两种情况下,用户都无能为力(除非他们一方发生损坏,例如缓存或 Cookie 不匹配)。

避免重定向循环很重要,因为它们会完全破坏用户体验。

另见