nginx自动添加url结尾的斜杠的事故处理
nginx自动添加url结尾的斜杠的事故处理
事故发生场景
用户访问不带结尾“/”的url后,会发生301跳转,url从https变成了http,并在域名后面自动加上了第二个nginx配置的端口。
用户访问的 url 见下:
https://www.example.com/nginx/aixiaoxi
访问后301跳转的 url 见下:
http://www.example.com:41000/nginx/aixiaoxi/
外网的入口前端nginx配置为:
server {
listen 443 ssl;
server_name www.example.com;
location /nginx/ {
proxy_pass http://192.168.1.100:41000;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
后端nginx的配置为:
server {
listen 41000;
server_name _;
location /nginx/aixiaoxi {
try_files $uri $uri/ /nginx/aixiaoxi/index.html;
}
}
事故的原因分析
后端nginx发现请求是一个目录,而不是一个文件的时候,根据 HTTP 的规范,会自动在url末尾自动添加上“/”,并响应输出:
HTTP/1.1 301 Moved Permanently
Location: http://www.example.com:41000/nginx/aixiaoxi/
可以看到输出的是一个绝对url,且它是后端nginx根据请求拼凑出来的。
前端nginx请求的是“http://192.168.1.100:41000”,后端nginx就知道这是一次http请求,并不是https的,且请求的端口是41000。
所以拼凑出来的绝对url为“http://www.example.com:41000/nginx/aixiaoxi/”。
解决方案
要解决此事故,我们需要在后端nginx里控制响应标头“Location”就可以。
方案一
在后端nginx里,使用nginx 的absolute_redirect指令。通过关闭absolute_redirect,让nginx输出相对路径。
这是最优方案。
基本语法:
absolute_redirect on | off;
默认值:on(使用绝对 URL,如http://example.com/new/path)
作用域:http、server、location
在 server 里配置:
server {
listen 41000;
server_name _;
absolute_redirect off; # 全局禁用绝对重定向
location /nginx/aixiaoxi {
try_files $uri $uri/ /nginx/aixiaoxi/index.html;
}
}
在 location 里配置:
server {
listen 41000;
server_name _;
location /nginx/aixiaoxi {
try_files $uri $uri/ /nginx/aixiaoxi/index.html;
absolute_redirect off;
}
}
配置完成后,访问“https://www.example.com/nginx/aixiaoxi”后,输出为:
HTTP/1.1 301 Moved Permanently
Location: /nginx/aixiaoxi/
此时 Location 为相对路径,浏览器就可以自动跳转到“https://www.example.com/nginx/aixiaoxi/”。
方案二
避免nginx自动补全“/”导致的301跳转,在后端nginx里强制指定 301 跳转的地址。
server {
listen 41000;
server_name _;
location /nginx/aixiaoxi {
if ($request_uri = /nginx/aixiaoxi) {
return 301 https://$host$request_uri/;
}
try_files $uri $uri/ /nginx/aixiaoxi/index.html;
}
}
配置完成后,访问“https://www.example.com/nginx/aixiaoxi”后,输出为:
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/nginx/aixiaoxi
此时 Location 为绝对路径,浏览器就可以自动跳转到“https://www.example.com/nginx/aixiaoxi/”。
这种方案会导致每次请求都要判断一次,不够完美。
并且还有一个缺点:
当用户直接访问后端nginx且没有在url末尾添加“/”时,访问会报错。
http://192.168.1.100:41000/nginx/aixiaoxi
访问后,响应输出的 Location 为:
HTTP/1.1 301 Moved Permanently
Location: https://192.168.1.100:41000/nginx/aixiaoxi/
使用方案一,却不会有这种问题。

浙公网安备 33010602011771号