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/

使用方案一,却不会有这种问题。

posted @ 2025-07-04 13:14  梦魇  阅读(99)  评论(0)    收藏  举报