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)
HTTP 转 HTTPS 协议(302)
跳转登陆页面(302)
自动刷新页面(302)
不同平台站点切换(302)
针对一些特殊请求,常常需要提供一个临时的响应页面,以避免用户后续操作影响到正常的服务流程。常见的场景有两种:
网址 URL 劫持属于 302 重定向的恶意应用。为了描述网址劫持的现象,这里先假设一个站点 A,通过 302 重定向到另一个站点 B。
对于大部分的搜索引擎,当收到 302 重定向响应时,一般只需要去抓取目标网址,也就是站点 B 的资源就可以了,这种情况下是不存在网址劫持的。但是,有些搜索引擎,如 Google,并不能总是抓取到目标网址,仍然可能在搜索结果中返回站点 A。如果此时站点 A 是你期望提供服务的网站,而站点 B 是你的竞争对手的网站,那么每次 Google 搜索结果显示你的站点 A,但用户点击后实际访问的缺失站点 B,这种情况就是网址 URL 劫持。本来属于站点 A 的访问流量,由于 302 重定向的恶意应用,被引导到站点 B 中。
302 重定向造成的网址劫持现象,已经是一个存在已久的问题,很多企业都在研究解决方案,然而这并没有什么特别好的处理方法。从搜索的实际效果来看,网址劫持问题有一定的缓解,但并不能完全解决。
使用重定向机制的好处很多,但如果大量配置重定向响应的话,容易导致严重的服务问题,其中重定向的死锁是比较严重的一种。
当重定向的路径被指定到之前的某个站点资源时,就会产生一个重定向循环,不会有一个最终的页面响应。这种情况通常属于服务器错误,但是,由于重定向可能发生在多台服务器之间,对于单个服务器而言,它是无法感知整个重定向链路的,因此一般无法对这个死锁问题进行检测。
在这种情况下,浏览器会负责进行检测,然后返回错误信息,告知用户。然而用户对此几乎完全无能为力,除非刷新重定向缓存后能逃脱原来的循环。因此在实际应用中,一定要避免出现重定向循环,这类问题一旦出现,严重影响用户的体验,就是十分严重的生产事故了。
使用 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;