此文档记录鄙人在生产环境中遇到的一些rewrite需求。常规的一些rewrite需求可能分分钟就配好了,但有些复杂的需求最长的花了4个小时去研究。为了避免这种屡战屡败的现象发生,故记录文档,缩短耗时。
常规需求rewrite
一般rewrite需求都是对于SEO的需求,一些url会以302的状态码跳转,会影响到谷歌排名。需要将url跳转改为301跳转(永久重定向)。所以需要通过nginx来做301rewrite。
例:
rewrite /cn/service/onsite/detail https://support.oppo.com/cn/onsite-repair/ permanent;
不需要正则匹配的情况
带参数的url-rewrite后-保留参数
#例:
#https://example.com/cn/show/?q=xxx -->
#https://example.com/cn/getinfo/?q=xxx
if ( $arg_q ) { rewrite /cn/show/ https://example.com/cn/getinfo/ permanent;}
备注:
判断参数q如果存在。/cn/getinfo/结尾没有带?,所以会把参数附在后面。
带参数的url-rewrite后-去除参数
#例:
#https://example.com/cn/show/?aid=1234 -->
#https://example.com/cn/getinfo/
if ( $request_uri = "/cn/show/?aid=1234" ) {rewrite (.*) https://example.com/cn/getinfo/? permanent;}
备注:
nginx的参数$uri获取的uri是不带参数的,可以通过$request_uri获取带参数uri。从而进行if判断。? 去掉转发后的参数。
需要正则匹配的情况
带参数url-rewrite后-参数的key变&value不变
#例:
#https://example.com/cn/show/?q=xxxx -->
#https://example.com/cn/getinfo/?kw=xxxx
#ps:valu值xxxx是变量,301rewrite后改变key,但是value的值不变。
if ( $arg_q ){ rewrite /cn/show/ https://example.com/cn/getinfo/?kw=$arg_q? permanent;}
带参数url-需要正则匹配参数的value
#例:
#https://example.com/cn/show?city=xxxx (xxxx为1-4位数字) -->
#https://example.com/cn/getinfo/
#ps:需要参数的value满足条件的情况下,301转发到/cn/getinfo/且不保留参数。
if ( $arg_city ~ "[0-9]{1,4}" ) {rewrite /cn/show https://example.com/cn/getinfo/? permanent;}
备注:
前面提到,可以通过$request_uri获取带参数的uri从而做if判断。但是在实际配置过程中发现,如果要对参数的value进行正则匹配的话,通过 if ( $request_uri ~ “/cn/service/map?city=正则表达式”)这样的方式无法对uri中参数的value进行正常的匹配。所以上述例子中用到了$arg_parameterName这个nginx内置参数来正则匹配参数的value。
带多个参数的url rewrite
#例:
#https://example.com/cn/shwo?id=123&name=456&age=20 -->
#https://example.com/cn/getinfo/
#ps:301后去除参数
set $cnshwo "";
if ( $arg_id = 123 ) {
set $cnshwo "1";
}
if ( $arg_name = %456 ) {
set $cnshwo "${cnshwo}1";
}
if ( $arg_age = 20 ) {
set $cnshwo "${cnshwo}1";
}
if ( $help657 = 111 ) {
rewrite (.*)$ https://example.com/cn/getinfo/? permanent;
}
备注:
nginx不可以写多重if判断。所以要判断多种情况同时满足时,可以使用一个中间变量作为判断依据。
正则判断非某字段开头或结尾
#规则:不以/cn/.*开头;中间包含html;不以?.*结尾。
if ( $request_uri ~* ^(?!/cn/.*).*.html.*(?<!\?).*$ ) { rewrite /(.*).htm$ https://other-example.com/$1/ permanent; }
备注:
正则表达式,^(?!str)不以str开头;(?<!str)$不以str结尾。
参考文档
https://segmentfault.com/a/1190000019266662https://segmentfault.com/a/1190000019266662
重定向POST请求
用rewrite重写POST请求的话,重写后的POST请求会变成GET请求,且body中的信息也会丢失。
对于POST请求需要进行307重定向。
if ( $request_uri ~ ^(/.*)/-/protected_branches$ ) {return 307 http://10.10.10.10:80/api?a=$1;}
备注:将uir为/xxxx/-/protected_branches的请求,307重定向到10.10.10.10服务器、80端口、uri=/api;url中query参数a等于匹配到的/xxxx的值。
map优化大量rewrite场景
场景:如果我们有上千条重定向规则需要去配置,且没有办发用正则去减少条目。这样的情况下,为了提高效率,可以使用map去实现。
首先,我们需要先准备map的文件。每行一个重定向,空格分隔并以冒号终止。
文件路径:/var/www/vhosts/acme.com/redirects/redirect.map
格式如下:
/source-url-1 https://acme.com/dest-url-1:
/source-url-2 https://acme.com/dest-url-2:
第二步,再http下配置
map_hash_max_size 4096;
map_hash_bucket_size 256;
map $request_uri $new_uri {
include /var/www/vhosts/acme.com/redirects/redirect.map
}
第三步,我们在对应的server下或者server的location下,使用map文件获取的路径进行rewrite
if ($new_uri != "") {
rewrite ^(.*)$ $new_uri permanent;
}
参考文档