HTTP 重定向的应用场景
HTTP 重定向在实际生产中有很多应用场景,但是需要注意的是应该尽可能减少其使用数量,毕竟每一次重定向都会在一定程度上降低服务性能。
常见应用场景
域名别称
通常情况下,一个站点资源只会对应一个 URL,但是考虑到用户习惯、站点维护、流量控制等因素,常常需要为一个站点资源设定多个 URL,即不同的域名。
根据以下不同的目的,可以在实际生产环境中设定域名别称:
-
扩大站点的用户访问命中(302)
- 一个典型的例子就是
https://www.baidu.com/ ,这个是其标准的 URL 站点资源,但是用户在浏览器输入链接访问时,往往不是输入完整的 URL,而是输入容易记忆的标志性片段,如 baidu.com/ 、 www.baidu.com/ 、 https://baidu.com/ 、 http://baidu.com/ 、 http://www.baidu.com/ 等。除此之外,还可以配置一些常见的同义词,或者当前域名常见的错误拼写域名别称。 -
域名链接已变更(301)
- 当原来的站点更换域名后,希望用户仍然可以通过原来的 URL 访问到当前站点时,可以配置原来的域名作为别称。
- 短域名用于传播,访问后重定向至其真实的完整地址。
- 解决跨域问题
-
HTTP 转 HTTPS 协议(302)
- 某些站点会将 HTTP 的请求强制重定向为 HTTPS 请求。
- 谷歌认为 301 是迁移 HTTP 至 HTTPS 的最佳方法,然而各大浏览器都是默认使用 302 。。。
中间页面跳转
-
跳转登陆页面(302)
- 未登录状态访问某个页面时,需要跳转到鉴权页面完成登陆后,再跳转回原来的页面。
-
自动刷新页面(302)
- 完成某项操作后,需返回上一级页面。如订单提交成功等。
-
不同平台站点切换(302)
- 同一个站点在PC端与移动端常常提供不同的访问链接,在响应时需要判断当前的设备进而控制是否需要重定向。
临时响应
针对一些特殊请求,常常需要提供一个临时的响应页面,以避免用户后续操作影响到正常的服务流程。常见的场景有两种:
- 请求的处理耗时较长(303)
- 如 请求内容较多的 GET、POST 请求,或者 后置处理的 DELETE 请求。在这种情况下通常会返回一个 303 重定向响应,链接到一个新的页面,告知用户该请求已经被接收处理,会通过其他方式通知用户请求的处理进展,或者支持用户取消上次操作。
- 修改服务器状态的请求(303)
- 虽然有些服务在服务器端会保证其操作的幂等性,但为了提高服务资源的利用率以及保证服务的性能,我们并不希望用户由于刷新页面等操作,导致重复发送如同 PUT、POST 或者 DELETE 请求。因此在这种情况下通常会返回一个 303 重定向响应,跳转到另一个新的并携带响应信息的页面,此时如果用户进行页面刷新,也只会刷新当前页面,不会重复提交之前的请求。
常见问题
网址劫持(URL hijacking)
网址 URL 劫持属于 302 重定向的恶意应用。为了描述网址劫持的现象,这里先假设一个站点 A,通过 302 重定向到另一个站点 B。
对于大部分的搜索引擎,当收到 302 重定向响应时,一般只需要去抓取目标网址,也就是站点 B 的资源就可以了,这种情况下是不存在网址劫持的。但是,有些搜索引擎,如 Google,并不能总是抓取到目标网址,仍然可能在搜索结果中返回站点 A。如果此时站点 A 是你期望提供服务的网站,而站点 B 是你的竞争对手的网站,那么每次 Google 搜索结果显示你的站点 A,但用户点击后实际访问的缺失站点 B,这种情况就是网址 URL 劫持。本来属于站点 A 的访问流量,由于 302 重定向的恶意应用,被引导到站点 B 中。
302 重定向造成的网址劫持现象,已经是一个存在已久的问题,很多企业都在研究解决方案,然而这并没有什么特别好的处理方法。从搜索的实际效果来看,网址劫持问题有一定的缓解,但并不能完全解决。
循环重定向导致的死锁
使用重定向机制的好处很多,但如果大量配置重定向响应的话,容易导致严重的服务问题,其中重定向的死锁是比较严重的一种。
当重定向的路径被指定到之前的某个站点资源时,就会产生一个重定向循环,不会有一个最终的页面响应。这种情况通常属于服务器错误,但是,由于重定向可能发生在多台服务器之间,对于单个服务器而言,它是无法感知整个重定向链路的,因此一般无法对这个死锁问题进行检测。
在这种情况下,浏览器会负责进行检测,然后返回错误信息,告知用户。然而用户对此几乎完全无能为力,除非刷新重定向缓存后能逃脱原来的循环。因此在实际应用中,一定要避免出现重定向循环,这类问题一旦出现,严重影响用户的体验,就是十分严重的生产事故了。
Nginx 强制 HTTP 转 HTTPS 导致请求失败
使用 Nginx 配置重定向实现 HTTP 请求转 HTTPS 协议时,常常会看到类似的报错信息:
GET request not supported
原来是 GET 请求的,不会出现这种错误信息,通常原来是 POST 请求的,在转发后会改变成 GET 请求。如果接口原来不同时支持 GET 和 POST 请求,那么强制转化 HTTP 协议至 HTTPS 后,就会出现上述错误;即便接口原来同时支持这两个请求方法,由于两者的传参方式不同,在改变成 GET 方法后,可能也会由于没有请求参数而导致服务请求失败。
以上情形,无论是使用 301 还是 302 重定向,都可能会出现。因此人们后来提出了与 301、302 相对应的 308、307 重定向状态码,其含义基本一致,唯一的不同点是,308 和 307 重定向可以保持原来的请求方法,即保持原来的 POST 请求。
Nginx 配置文件的具体配置示例如下:
return 307 https://$domain$uri;
#return 308 https://$domain$uri;
|