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] 网页由于不可预见的原因暂时不可用。
303 查看其他 GET方法不变。其他方法更改GET(主体丢失)。 用于在PUTPOST之后重定向,以便刷新结果页面不会重新触发操作。
307 临时重定向 方法和主体不变 网页由于不可预见的原因暂时不可用。当站点上提供非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。

您不希望破坏这些链接,因为它们会带来有价值的用户并帮助您的搜索引擎优化,因此您会设置从旧 URL 到新 URL 的重定向。

注意:此技术确实适用于内部链接,但请尽量避免使用内部重定向。重定向会产生明显的性能成本(因为会发生额外的 HTTP 请求)。如果可以通过更正内部链接来避免这种情况,则应更正这些链接。

对不安全请求的临时响应

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

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

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

对长时间请求的临时响应

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

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

Apache

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

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

Apache 配置文件
<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 集合。

Apache 配置文件
RedirectMatch ^/images/(.*)$ https://images.example.com/$1

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

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

Apache 配置文件
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 内部服务器错误。如果您在修改服务器配置后不久遇到此错误,则很可能是重定向循环。

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

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

…而 Chrome 显示

此网页存在重定向循环。

在这两种情况下,用户都无能为力(除非他们的客户端出现问题,例如缓存或 Cookie 不匹配)。

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