美文网首页
nginx rewrite

nginx rewrite

作者: Daisy小朋友 | 来源:发表于2020-04-14 14:59 被阅读0次

    需求:

    之前公司使用的是apache,现在想把apache撤掉需要把之前apache上rewrite转移到nginx

    遇到的问题:

    Q1 :不确定rewrite写的对不对

    A1:打开nginx rewrite log

    修改nginx配置文件为debug
    error_log  logs/error_www2.log  debug;
    就可以在error_www2.log 中看到rewrite log
    

    apache rewrite log查看方法

    在配置文件的rewrite下面log上面添加
    #RewriteRule........
    LogLevel alert rewrite:trace8
    #ErrorLog "|/usr/local/apache/bin/rotatelogs -l /data/logs/httpd/rewrite.5pao.com-error.log 86400"
    就可以在rewrite.5pao.com-error.log中查看rewrite日志了
    

    Q2:已经确定rewrite写的没错(日志中可正常看到转发),但是转发到上游tomcat后地址还是无法被找到,此功能用于搜索。

    排查步骤:

    P1:

    在网页搜索编码号时返回正常,但是搜索中文就会变成404
    中文搜索时tomcat日志报错:

    2020-04-08 15:36:36,493  INFO UserFilter:48 - ***[shopmm]有恶意参数入侵,参数为:sptype=3&xinyu=&xyfrom=&xyto=2&xnyuzk=&shopstype=111&stprice=&enprice=&jiasg=&sarea=&shophour=&sthaopn=&xunibi=&spingf=&skouf=&sdaih=&shuoy=&sid=&zhank=&doubletab=&teshuzz=%e5%8d%8e%e5%8d%97&xinyuorder=&pxfs=&sjpx=&lrpx=&yyepx=&qitype=&qigohu=&brandid=&zizhiid=&page=1
    

    参数不能被识别,查看代码


    图片.png

    此时查看可能和中文转码有关

    P2:

    查看nginx转过来的参数

    spType=%26sbtype=%26zctype=%26shopsType=%26stPrice=%26enPrice=%26jiasg=%26sarea=%26shopHour=%26shuoy=%26steam=%26sjyan=%26sid=%25E5%258D%258E%25E4%25B8%259C%26zhank=%26doubleTab=%26xinyuOrder=%26pxfs=%26sjpx=%26lrpx=%26yyepx=%26brandId=%26sctype=&nsrzz=&page=1.html
    

    nginx 最后rewrite的参数是被二次转码的,二次转码的参数传递给上游tomcat端不被识别

    P3:

    查看原apache配置时的rewrite log

    spType=&sbtype=&zctype=&shopsType=&stPrice=&enPrice=&jiasg=&sarea=&shopHour=&shuoy=&steam=&sjyan=&sid=%E5%8D%8E%E4%B8%9C&zhank=&doubleTab=&xinyuOrder=&pxfs=&sjpx=&lrpx=&yyepx=&brandId=&sctype=&nsrzz=&page=1.html
    

    apache最后rewrite的参数是一次转码的,传递个tomcat后可被正常使用

    P4:

    经过多次测试发现,这个问题应该和rewrite和apache中文编码有关,
    http://www.jsons.cn/urlencode/
    转码发现,nginx rewrite后的指解码后可以得到apache rewrite的值参数值就可以被tomcat接受

    现在有两种解决方法:

    a 修改代码,添加urldecoder转码


    图片.png

    b 修改nginx,让它只转码一次,这样参数到tomcat中就可以被识别

    P5:

    仔细查看nginx rewrite日志发现,(我配置的nginx 配置文件中有多次rewrite)
    前几次的rewrite都是一次转码,最后一次带有args参数后就被再次转码

    rewritten data: "/shopmm/tmp--1.htmlspType=32&sbtype=&zctype=&shopsType=&stPrice=&enPrice=&jiasg=&sarea=&shopHour=&shuoy=&steam=&sjyan=&sid=%E5%B0%8F%E7%BA%A2%E4%B9%A6&zhank=&doubleTab=&xinyuOrder=&pxfs=&sjpx=&lrpx=&yyepx=&brandId=&sctype=", args: ""
    rewritten data: "/qitaIndexNew.do", args: "spType=32%26sbtype=%26zctype=%26shopsType=%26stPrice=%26enPrice=%26jiasg=%26sarea=%26shopHour=%26shuoy=%26steam=%26sjyan=%26sid=%25E5%25B0%258F%25E7%25BA%25A2%25E4%25B9%25A6%26zhank=%26doubleTab=%26xinyuOrder=%26pxfs=%26sjpx=%26lrpx=%26yyepx=%26brandId=%26sctype=&nsrzz=&page=1"
    
    所以思路是:将args解码一次并传递给tomcat即可

    参考:

    https://my.oschina.net/monkeyzhu/blog/997815

    P6:

    解码需要使用到set_unescape_uri,此命令需要单独安装set-misc-nginx-module模块

    安装方法:

    set_unescape_uri模块安装

    cd /usr/local/src
    wget https://github.com/openresty/set-misc-nginx-module/archive/v0.31.tar.gz
    wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
    tar zxvf v0.31.tar.gz
    tar zxvf v0.3.0.tar.gz
    找到源码包
    ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_sub_module --with-http_realip_module --with-http_addition_module --with-http_gzip_static_module --with-http_stub_status_module --with-pcre --with-http_stub_status_module --with-http_dav_module  --add-module=/soft/src/lua-nginx-module-0.10.13 --add-module=/soft/src/ngx_devel_kit-0.3.0 --add-module=/soft/src/set-misc-nginx-module-0.31
    注意添加最后两条:
    --add-module=/soft/src/ngx_devel_kit-0.3.0 --add-module=/soft/src/set-misc-nginx-module-0.31
    且--add-module=ngx_devel_kit一定要早于--add-module=set-misc-nginx-module
    make 
    注意不需要make install
    将objs/nginx 替换原有sbin/nginx即可
    

    参考:

    https://blog.csdn.net/tao_627/article/details/78991287

    使用方法:
    set_unescape_uri
    语法: set_unescape_uri $dst <src> / set_unescape_uri $dst
    默认值: no
    配置段:location, location if
    当两个参数时,该指令将非转义第二个参数<src>的值作为URI一部分,并分配第一个参数变量$dst分配结果。如:
    location /test {
    set_unescape_uri $key $arg_key;
    echo $key;
    }
    当请求GET /test?key=hello+world%21时,得到:hello world!。
    注意: nginx标准的变量$arg_PARAMETER保存原始的URI参数(转义过的),因此需要set_unescape_uri指令来非转义先。
    
    当单个参数时,该指令将修改参数变量位置,如:
    location /test {
    set $key $arg_key;
    set_unescape_uri $key;
    echo $key;
    }
    当请求GET /test?key=hello+world%21时,得到:hello world!。
    

    参考:

    http://www.ttlsa.com/nginx/nginx_set-misc-nginx-module-module-description/

    P7

    在原来rewrite基础上添加

    set_unescape_uri $new_args $args ;
    rewrite ^(.*)$  /tmallIndexNew.do?;
    rewrite ^(.*)$  /tmallIndexNew.do?$new_args break;
    
    

    set_unescape_uri new_argsargs ;
    首先将得到的参数解码后赋予给新值

    $args值:"spType=32%26sbtype=%26zctype=%26shopsType=%26stPrice=%26enPrice=%26jiasg=%26sarea=%26shopHour=%26shuoy=%26steam=%26sjyan=%26sid=%25E5%25B0%258F%25E7%25BA%25A2%25E4%25B9%25A6%26zhank=%26doubleTab=%26xinyuOrder=%26pxfs=%26sjpx=%26lrpx=%26yyepx=%26brandId=%26sctype=&nsrzz=&page=1"
    $new_args值:spType=32&sbtype=&zctype=&shopsType=&stPrice=&enPrice=&jiasg=&sarea=&shopHour=&shuoy=&steam=&sjyan=&sid=%E5%B0%8F%E7%BA%A2%E4%B9%A6&zhank=&doubleTab=&xinyuOrder=&pxfs=&sjpx=&lrpx=&yyepx=&brandId=&sctype=&nsrzz=&page=1
    
    rewrite ^(.*)$  /tmallIndexNew.do?;
    rewrite ^(.*)$  /tmallIndexNew.do?$new_args break;
    重新rewrite之前的url,为什么要加
    rewrite ^(.*)$  /tmallIndexNew.do?; 
    ”因为直接rewrite ^(.*)$  /tmallIndexNew.do?$new_args break;得到的url会出现两个$args值,影响搜索(下一个rewrite会带有上一个rewrite的参数)
    所以曲折一下,先获取参数值,再rewrite没有参数页面,再rewrite解码后传递的参数的url
    

    此时域名可以被正常搜索不报404了

    知识点

    1 中文转码

    a. 为什么要进行url编码
    b. 怎么编码
    c. 有哪些细节需要注意

    url编码是一种传输url的机制, 个人认为最主要的作用是区分字符是否有特殊意义. 我们都知道有许多字符在url中是有特殊含义的, 比如?作为参数开始的标志, 又比如&作为参数切分标志. 因此如果想要让这些 字符保留字符原本含义就需要对它们进行url编码. 另外一个作用是用来传递非可视字符. url编码的主要内容是: 0-9A-Za-z以及-, ~, ., ~无需通过编码即可传输(普通字符), 而以下字符(保留字符):

    ! * ( ) ; : @ & = + $ , / ? # [ ]

    如果要当作字符常量对待则需要经过编码. 另外其他的字符都需要进过url编码来进行传输. 编码形式是%后跟对应的十六进制形式.

    这里需要注意的有两点:

    a. 编码并非是强制性, 即使是普通字符我们也可以进行编码然后进行传输
    b. 在参数部分, 空格会被编码成+而非%25, 参见这里The application/x-www-form-urlencoded type一节, 所以会造成经过base64编码的内容直接传输时, 加号在经过解码之后变为空格. 针对这个问题衍生出了其他的base64方式(主要是替换了/, +)

    参考:

    http://blog.aka-cool.net/blog/2013/07/09/url-encode-in-nginx/

    url了解及其转义参考

    https://www.cnblogs.com/upyun/p/8267334.html

    2 nginx last和break

    last: 相当于Apache的[L]标记,表示完成rewrite
    break: 停止执行当前虚拟主机的后续rewrite指令集
    redirect: 返回302临时重定向,地址栏会显示跳转后的地址
    permanent: 返回301永久重定向,地址栏会显示跳转后的地址
    这里 last 和 break 区别有点难以理解:
    last一般写在server和if中,而break一般使用在location中
    last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
    break和last都能组织继续执行后面的rewrite指令

    3 变量

    $request_uri变量

    这个$request_uri就是完整url中刨去最前面$host剩下的部分,比如http://www.baidu.com/pan/beta/test1?fid=3这个url,去掉www.baidu.com剩下的就是了,日志里会看到打印出来的$request_uri其实是/pan/beta/test1?fid=3。如果只访问www.baidu.com,$request_uri里也会有个/的
    if ($request_uri ~* "^/$") 表示url中只有域名,后面不跟任何东西,比如www.baidu.com。
    if ($request_uri ~* "test") 表示域名后面那串儿只要包含test这个关键词,就可匹配成功。比如www.baidu.com/pan/beta/test3
    

    $args变量
    举栗子:
    http://localhost:8080/test?a=0&b=1&c=2'
    args:a=0&b=1&c=2值?后面的变量
    注意:多次rewrite后,下一次的rewrite会带着前一个args,导致args中会有多于变量。
    默认的情况下,Nginx在进行rewrite后都会自动添加上旧地址中的参数部分,而这对于重定向到的新地址来说可能是多余。虽然这也不会对重定向的结果造成多少影响
    参考:

    今天在给某网站写rewrite重定向规则时,碰到了这个关于重定向的参数处理问题。默认的情况下,Nginx在进行rewrite后都会自动添加上旧地址中的参数部分,而这对于重定向到的新地址来说可能是多余。虽然这也不会对重定向的结果造成多少影响,但当你注意到新地址中包含有多余的“?xxx=xxx”时,心里总还是会觉得不爽。那么该如何来处理这部分的内容呢?看了下面两个简单的例子你就会明白了。
    
    例如:
    把http://example.com/test.php?para=xxx 重定向到 http://example.com/new
    若按照默认的写法:rewrite ^/test.php(.*) /new permanent;
    重定向后的结果是:http://example.com/new?para=xxx
    如果改写成:rewrite ^/test.php(.*) /new? permanent;
    那结果就是:http://example.com/new
    
    所以,关键点就在于“?”这个尾缀。假如又想保留某个特定的参数,那又该如何呢?可以利用Nginx本身就带有的$arg_PARAMETER参数来实现。
    
    例如:
    把http://example.com/test.php?para=xxx&p=xx 重写向到 http://example.com/new?p=xx
    可以写成:rewrite  ^/test.php   /new?p=$arg_p?  permanent;
    
    只求结果的朋友可以直接忽略前面的内容,看这里:
    
    rewrite  ^/test.php  /new  permanent;       //重写向带参数的地址
    
    rewrite  ^/test.php  /new?  permanent;      //重定向后不带参数
    
    rewrite  ^/test.php   /new?id=$arg_id?  permanent;    //重定向后带指定的参数
    
    
    permanent是永久重定向参数,根据需要去掉也可以,不过最好是带有。
    参考301重定向与302重定向的区别
    地址:[https://blog.csdn.net/zhsh87/article/details/8191264](https://blog.csdn.net/zhsh87/article/details/8191264)
    
    

    query_string 此变量与args相同
    其它变量可参考

    https://www.cnblogs.com/pycode/p/6588896.html

    4 解决Nginx反向代理不会自动对特殊字符进行编码的问题

    参考:

    https://blog.csdn.net/LLittleF/article/details/93879077

    相关文章

      网友评论

          本文标题:nginx rewrite

          本文链接:https://www.haomeiwen.com/subject/dhyzmhtx.html