一. 重定向循环
我们在网上冲浪时,有时候会遇到浏览器提示以下错误:
ERR_TOO_MANY_REDIRECTS
即重定向次数过多,该错误会导致用户无法浏览所需内容。
为什么会出现该错误呢?
该错误通常是由于web服务器配置错误造成的,一个典型的情况就是重定向循环。例如:针对两个url:
url_a
url_b
web服务器对url_a配置了以下重定向:
当用户请求url_a时,重定向至url_b。
如此,当用户访问url_a,用户的实际请求url会发生变化,请求从url_a跳转至url_b。
此时,如果web服务器对url_b也配置了重定向:
当用户请求url_b时,重定向至url_a。
如此,就会产生重定向循环:当用户访问url_a,用户的实际请求url会发生变化,请求从url_a跳转至url_b;请求到达url_b后,又会跳转至url_a。
以上是一种产生重定向循环错误比较简单直观的场景。在现实场景中,重定向循环可能不会这么简单。例如,造成重定向循环的循环链条中,包含的url可能在2个以上:
url_a > url_b > url_c > url_d > url_a
这显然会增加问题排查的难度。
二. CDN与重定向循环
在我的实际经验中,还有一种情况是CDN的问题,当CDN配置与源服务器配置不兼容时,也会产生重定向循环。
例如:
对以下站点:
进行CDN加速,配置源站地址为:
wwwcdn.site.com
用户可通过以下url访问站点:
Custom Application Development Software for Business – Salesforce.com
Custom Application Development Software for Business – Salesforce.com
以上url的区别仅在于使用的协议不同,一个是http,一个是https。
由于启用了CDN,用户的请求实际不会直接到达源服务器,而是被CDN的边缘节点拦截。根据缓存情况,CDN边缘节点再通过以下url请求源服务器:
同样,CDN的两个回源url区别也仅在于协议不同。事实上,可以配置CDN回源所使用的协议,基于性能考虑,通常配置CDN回源使用http协议,也就是说CDN回源使用以下url:
至此,一个经过CDN加速的站点就正常运行起来了。
重定向循环的产生
假设此时有了新的需求,要求用户必须使用https协议来访问站点。我们当然没法强制用户的浏览器中输入域名的时候打上https,解决办法就是做重定向。如果重定向在源服务器上来实现,需修改源服务器web配置(nginx):
server {
listen 80;
listen 443 ssl;
server_name www.site.com wwwcdn.site.com;
ssl_certificate /etc/nginx/ssl/site.com.fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/site.com.key;
access_log off;
root /home/site/guangzhuiyuan/appdownload/unipixel;
if ($scheme = http) {
rewrite "^/(.*)$" https://$server_name/$1 permanent;
}
...
}
这里添加了一个rewrite指令,当用户使用http协议时,强制跳转至https协议。然而,当用户使用以下url访问站点时:
Custom Application Development Software for Business – Salesforce.com
浏览器提示:
ERR_TOO_MANY_REDIRECTS
重定向循环出现了,梳理一下请求过程:
1. 用户通过浏览器访问Custom Application Development Software for Business – Salesforce.com。
2. 请求到达CDN。
3. CDN通过http://wwwcdn.site.com回源。
4. 源服务器接收到请求http://wwwcdn.site.com。
5. 源服务器执行重定向,用户请求跳转为CDN – Home。
6. 请求到达CDN。
7. CDN通过http://wwwcdn.site.com回源。
8. 源服务器接收到请求http://wwwcdn.site.com。
9. 源服务器执行重定向,用户请求跳转为CDN – Home。
… …
解决办法
梳理后可以知道,问题的核心在于CDN以http协议回源,而源服务器对http协议进行了重定向,触发用户的二次请求,并造成CDN以http协议再次回源,如此不断循环。解决办法便在于打断循环链条。
方法一:
用户端http到https的重定向交由CDN负责,不在源服务器执行重定向。
方法二:
用户端http到https的重定向由源服务器负责,修改CND回源协议为https。
方法三:
拆分www.site.com和wwwcdn.site.com为两个独立的server配置,不要放置的同一个nginx server配置块中,并且,www.site.com做重定向,wwwcdn.site.com不做重定向。