我正在使用以下 nginx 重写规则,但我不明白为什么会出现以下结果。
server {
server_name old.example.com;
listen 80;
listen [::]:80;
rewrite ^/.*-f(\d+)/.*-t(\d+)\.html$ https://new.example.com/view.php?f=$1&t=$2 permanent;
}
以下结果是正常的(url 以‘.html’结尾)。
$ curl --head "http://old.example.com/abcd-f15/efgh-t125.html"
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.6
Date: Sat, 02 May 2020 12:48:53 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://new.example.com/view.php?f=15&t=125
以下结果也是可以的(url 不以“.html”结尾)。
$ curl --head "http://old.example.com/abcd-f15/efgh-t125.htmlx"
HTTP/1.1 404 Not Found
Server: nginx/1.17.6
Date: Sat, 02 May 2020 12:50:26 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive
但是我不明白以下结果(url 不以 '.html' 结尾,但重写规则匹配)。
$ curl --head "http://old.example.com/abcd-f15/efgh-t125.html#x"
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.6
Date: Sat, 02 May 2020 12:51:53 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://new.example.com/view.php?f=15&t=125
答案1
让我们来看看RFC 3986,3关于 URL 语法:
foo://example.com:8042/over/there?name=ferret#nose \_/ \______________/\_________/ \_________/ \__/ | | | | | scheme authority path query fragment | _____________________|__ / \ / \ urn:example:animal:ferret:nose
我们感兴趣的是分段,它的定义在第 3.5 节:
片段标识符在信息检索系统中发挥着特殊作用,是客户端间接引用的主要形式,允许作者明确标识现有资源中仅由资源所有者间接提供的方面。因此,片段标识符不用于 URI 的特定方案处理;相反,片段标识符在取消引用之前与 URI 的其余部分分离,因此片段本身内的标识信息仅由用户代理取消引用,而与 URI 方案无关。
TL;DR: HTTP URL 的处理分段 #x
仅发生在客户端。
让我们用curl
a添加一些详细内容-v
,这样我们就可以更清楚地看到这一点:
$ curl --head "http://old.example.com/abcd-f15/efgh-t125.html#x"
> HEAD /abcd-f15/efgh-t125.html HTTP/1.1
> Host: old.example.com
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.17.6
< Date: Sat, 02 May 2020 12:51:53 GMT
< Content-Type: text/html
< Content-Length: 169
< Connection: keep-alive
< Location: https://new.example.com/view.php?f=15&t=125
我相信从中您已经可以推断出为什么这是您预期的行为rewrite
。
重定向后片段会发生什么?除非你的Location:
头部专门指定了一个新的片段,否则客户端(网络浏览器)会保留它RFC 7231, 7.1.2:
如果(重定向)响应
Location
中提供的值3xx
没有片段组件,则用户代理必须处理重定向,就好像该值继承了用于生成请求目标的 URI 引用的片段组件(即,重定向继承原始引用的片段,如果有)。
简而言之,对于 URL http://old.example.com/abcd-f15/efgh-t125.html#x
:
如果
Location
没有指定新的片段(当前情况):> GET /abcd-f15/efgh-t125.html > Host: old.example.com < Location: https://new.example.com/view.php?f=15&t=125
->
https://new.example.com/view.php?f=15&t=125#x
y
如果您在规则中添加了片段rewrite
:> GET /abcd-f15/efgh-t125.html > Host: old.example.com < Location: https://new.example.com/view.php?f=15&t=125#y
->
https://new.example.com/view.php?f=15&t=125#y
新的 HTTP 请求也不包含片段,因此两者相同:
> GET /view.php?f=15&t=125 > Host: new.example.com