我正在尝试配置 nginx,以便可以通过两个不同的 URL 访问相同的静态内容没有任何重定向。
例如,如果客户端/path/to/A
在其浏览器中输入,我希望它检索与相同的内容/path/to/B
。
我尝试使用rewrite
,但在这种情况下 Nginx 似乎给我一个 301 重定向。
例如:
server {
root /my/www/data;
rewrite ^/path/to/A(.*)$ /path/to/B$1;
# Note: /my/www/data/path/to/B *does* actually exist on disk.
# However, the .../A version does not.
}
我猜想实现这一点的一种方法是使用符号链接/my/www/data/A
指向/my/www/data/B
,但我试图使用服务器配置而不是文件系统技巧来做到这一点。
我的问题是:
- 如何才能做到这一点?
- 在什么情况下
rewrite
模块会进行内部重定向,而不是向客户端发送 30x 代码?我无法从文档中清楚地看出。
注意:这与另一个问题非常相似:Nxginx 重写 URL 而不进行重定向 但是,那个不是很详细。
编辑:这是一个真实的配置,包含curl
命令等:
首先,配置:
server {
root /usr/share/nginx/www/mydata;
index index.html index.htm;
# Make site accessible from http://localhost/
server_name localhost;
location / {
try_files $uri $uri/ =404;
}
rewrite_log on;
rewrite ^/A(.*)$ /B$1 last;
}
现在,我的网络根目录内容:
$ find /usr/share/nginx/www/mydata/
/usr/share/nginx/www/mydata/
/usr/share/nginx/www/mydata/B
/usr/share/nginx/www/mydata/B/index.html
/usr/share/nginx/www/mydata/index.html
运行之后,我得到了以下结果curl
:
$ curl -i 'http://localhost/A'
HTTP/1.1 301 Moved Permanently
Server: nginx/1.2.1
...
Location: http://localhost/B/
...
<snipped>
不过,我确实注意到/A/
(带有尾部斜杠)并且/A/index.html
工作正常:
$ curl -i 'http://localhost/A/'
HTTP/1.1 200 OK
Server: nginx/1.2.1
<snip - I see data for B/index.html, as I expect>
( 结果相同/A/index.html
)。
因此,只有在第一种情况下我才会得到 301 重定向,尽管我的配置从未明确提到这样的事情。
这是怎么回事?
答案1
rewrite
通常nginx
不会导致 301 状态(除非明确配置),因此 301 可能是由nginx
配置的其他部分引起的。
rewrite
是实现您想要的正确方法,您的方法是正确的。
答案2
这是显示目录索引的 Web 服务器的默认行为,例如 Apache 也是如此。每当您仅请求“directory”时,它都会将您重定向到“directory/”之类的位置。
Apache 文档对此有明确说明,例如https://httpd.apache.org/docs/2.4/mod/mod_dir.html说
当服务器收到 URL 请求时,会发出“尾部斜杠”重定向http://服务器名称/foo/目录名称其中 dirname 是目录。目录需要尾部斜杠,因此 mod_dir 发出重定向到http://服务器名称/foo/目录名称/。
似乎 Nginx 文档对此比较含糊,例如http://nginx.org/en/docs/http/ngx_http_autoindex_module.html只是说:
ngx_http_autoindex_module 模块处理以斜杠字符 ('/') 结尾的请求并生成目录列表。通常,当 ngx_http_index_module 模块找不到索引文件时,请求会被传递给 ngx_http_autoindex_module 模块。
它没有解释前面的步骤,请求如何以斜线结尾,这似乎是隐含的。
网络上还有另一个关于同一问题的老问题:https://stackoverflow.com/questions/15555428/nginx-causes-301-redirect-if-theres-no-trailing-slash
答案3
好的,经过一些实验,我找到了一些不同的解决方案。
总而言之,我想/A
留/A
在用户的浏览器中(不重定向到/B
),但我仍然希望它显示来自的内容/B
。
选项1:使用符号链接(:这可行,但您需要访问文件系统。回避该问题。
选项 2:=
使用精确匹配 ( ) 位置块来防止自动尾部斜杠 301 重定向:
location = /A {
rewrite "" /B/;
}
# Note: the below should probably be inside a location block.
rewrite ^/A(.+)$ /B$1 last;
我从Nginx 文档:
如果没有尾部斜杠,则将返回带有代码 301 的永久重定向到附加了斜杠的请求 URI。如果不希望这样,可以定义 URI 和位置的精确匹配
选项 3:/A
使用从到 的重定向/A/
,但要手动执行,这样它就不会作为到 的(重写)重定向返回给客户端/B/
:
location = /A {
return 301 /A/;
}
location /A/ {
rewrite ^/A/(.*)$ /B/$1 last;
}
我最终选择了选项 3,因为它的/A
行为就像/B
,包括尾随斜杠重定向(但现在到正确的位置)。