设为首页 收藏本站
查看: 660|回复: 0

[经验分享] nginx rewrite规则语法

[复制链接]

尚未签到

发表于 2018-11-12 08:41:10 | 显示全部楼层 |阅读模式
最近在VPS上尝试配置安装一个网站,VPS安装了LNMP(Linux+Nginx+MySQL+php)在配置重定规则的时候经常遇到一些问题,直接用Apache的规则到Nginx下没起作用。原来Apache 重写的规则到nginx上还有一些不太一样的地方。
  这里只是简单记录一些学习示例,高手略过,新手可以看一下。
  Nginx Rewrite规则相关指令
  Nginx Rewrite规则相关指令有if、rewrite、set、return、break等,其中rewrite是最关键的指令。一个简单的Nginx Rewrite规则语法如下:
rewrite ^/b/(.*)\.html /play.php?video=$1 break;  如果加上if语句,示例如下:
if (!-f $request_filename)  
rewrite ^/img/(.*)$ /site/$host/images/$1 last;
  Nginx与Apache的Rewrite规则实例对比
  简单的Nginx和Apache 重写规则区别不大,基本上能够完全兼容。例如:
  Apache Rewrite 规则:
RewriteRule ^/(mianshi|xianjing)/$ /zl/index.php?name=$1 [L]  
RewriteRule ^/ceshi/$ /zl/ceshi.php [L]
  
RewriteRule ^/(mianshi)_([a-zA-Z]+)/$ /zl/index.php?name=$1_$2 [L]
  
RewriteRule ^/pingce([0-9]*)/$ /zl/pingce.php?id=$1 [L]
  Nginx Rewrite 规则:
rewrite ^/(mianshi|xianjing)/$ /zl/index.php?name=$1 last;  
rewrite ^/ceshi/$ /zl/ceshi.php last;
  
rewrite ^/(mianshi)_([a-zA-Z]+)/$ /zl/index.php?name=$1_$2 last;
  
rewrite ^/pingce([0-9]*)/$ /zl/pingce.php?id=$1 last;
  由以上示例可以看出,Apache的Rewrite规则改为Nginx的Rewrite规则,其实很简单:Apache的RewriteRule指令换成Nginx的rewrite指令,Apache的[L]标记换成Nginx的last标记,中间的内容不变。
  如果Apache的Rewrite规则改为Nginx的Rewrite规则后,使用nginx -t命令检查发现nginx.conf配置文件有语法错误,那么可以尝试给条件加上引号。例如一下的Nginx Rewrite规则会报语法错误:
rewrite ^/([0-9]{5}).html$ /x.jsp?id=$1 last;  加上引号就正确了:
rewrite “^/([0-9]{5}).html$” /x.jsp?id=$1 last;  Apache与Nginx的Rewrite规则在URL跳转时有细微的区别:
  Apache Rewrite 规则:
RewriteRule ^/html/tagindex/([a-zA-Z]+)/.*$ /$1/ [R=301,L]  Nginx Rewrite 规则:
rewrite ^/html/tagindex/([a-zA-Z]+)/.*$ http://$host/$1/ permanent;  以上示例中,我们注意到,Nginx Rewrite 规则的置换串中增加了“http://$host”,这是在Nginx中要求的。
  另外,Apache与Nginx的Rewrite规则在变量名称方面也有区别,例如:
  Apache Rewrite 规则:
RewriteRule ^/user/login/$ /user/login.php?login=1&forward=http://%{HTTP_HOST} [L]  Nginx Rewrite 规则:
rewrite ^/user/login/$ /user/login.php?login=1&forward=http://$host   last;  Apache与Nginx Rewrite 规则的一些功能相同或类似的指令、标记对应关系:
  Apache的RewriteCond指令对应Nginx的if指令;
  Apache的RewriteRule指令对应Nginx的rewrite指令;
  Apache的[R]标记对应Nginx的redirect标记;
  Apache的[P]标记对应Nginx的last标记;
  Apache的[R,L]标记对应Nginx的redirect标记;
  Apache的[P,L]标记对应Nginx的last标记;
  Apache的[PT,L]标记对应Nginx的last标记;
  允许指定的域名访问本站,其他域名一律跳转到http://www.aaa.com
  Apache Rewrite 规则:
RewriteCond %{HTTP_HOST}    ^(.*?)\.domain\.com$  
RewriteCond %{HTTP_HOST}    !^qita\.domain\.com$
  
RewriteCond %{DOCUMENT_ROOT}/market/%1/index.htm -f
  
RewriteRule ^/wu/$ /market/%1/index.htm [L]
  Nginx的if指令不支持嵌套,也不支持AND、OR等多条件匹配,相比于Apache的RewriteCond,显得麻烦一些,但是,我们可以通过下一页的Nginx配置写法来实现这个示例:
  Nginx Rewrite 规则:
if ($host ~* ^(.*?)\.domain\.com$) set $var_wupin_city $1;     set $var_wupin ‘1′;  
if ($host ~* ^qita\.domain\.com$)
  
    set $var_wupin ‘0′;
  
if (!-f $document_root/market/$var_wupin_city/index.htm)
  
     set $var_wupin ‘0′;
  
if ($var_wupin ~ ‘1′)
  
    rewrite ^/wu/$ /market/$var_wupin_city/index.htm last;}
  
  rewrite 的语法
  用法: rewrite 正则 替换 标志位
  作用域: server, location, if
  这个指令根据表达式来更改URI,或者修改字符串。指令根据配置文件中的顺序来执行。
  注意重写表达式只对相对路径有效。如果你想配对主机名,你应该使用if语句。
  nginx的rewrite规则参考:

  •   set
  •   if
  •   return
  •   break
  •   rewrite
  麻雀虽小,五脏俱全.只是简单的几个指令却可以做出绝对不输apache的简单灵活的配置.
  1.set  主要是用来设置变量用的,没什么特别的
  2.if  主要用来判断一些在rewrite语句中无法直接匹配的条件,比如检测文件存在与否,http header,cookie等,
  用法: if(条件) {…}
  - 当if表达式中的条件为true,则执行if块中的语句
  - 当表达式只是一个变量时,如果值为空或者任何以0开头的字符串都会当作false
  - 直接比较内容时,使用 = 和 !=
  - 使用正则表达式匹配时,使用
  ~ 大小写敏感匹配
  ~* 大小写不敏感匹配
  !~ 大小写敏感不匹配
  !~* 大小写不敏感不匹配
  随便一提,因为nginx使用花括号{}判断区块,所以当正则中包含花括号时,则必须用双引号将正则包起来.对下面讲到的rewrite语句中的正则亦是如此.
  比如 “\d{4}\d{2}\.+”
  - 使用-f,-d,-e,-x检测文件和目录,跟~类似,前置!则为”非”操作
  -f 检测文件存在
  -d 检测目录存在
  -e 检测文件,目录或者符号链接存在
  -x 检测文件可执行
  举例:
if ( $http_user_agent ~ MSIE ) { rewrite ^ (. * )$ /msie / $1 break; }  //如果UA包含”MSIE”,rewrite 请求到/msie目录下
if ( $http_cookie ~ * "id=([^;] +)(?:;|$)" ) { set $id $1;}  //如果cookie匹配正则,设置变量$id等于正则引用部分
if ( $request_method = POST ) { return 405; }  //如果提交方法为POST,则返回状态405 (Method not allowed)
if ( !-f $request_filename ) { break; proxy_pass http://127.0.0.1; }  //如果请求文件名不存在,则反向代理localhost
if ( $args ~ post=140 ) { rewrite ^ http: //example.com / permanent;}  //如果query string中包含”post=140″,永久重定向到example.com
  3.return  可用来直接设置HTTP返回状态,比如403,404等(301,302不可用return返回,这个下面会在rewrite提到)
  
  4.break  立即停止rewrite检测,跟下面讲到的rewrite的break flag功能是一样的,区别在于前者是一个语句,后者是rewrite语句的flag
  
  5.rewrite  最核心的功能(废话)
  其中标志位有四种
  break – 停止rewrite检测,也就是说当含有break flag的rewrite语句被执行时,该语句就是rewrite的最终结果
  last – 停止rewrite检测,但是跟break有本质的不同,last的语句不一定是最终结果,这点后面会跟nginx的location匹配一起提到
  redirect – 返回302临时重定向,一般用于重定向到完整的URL(包含http:部分)
  permanent – 返回301永久重定向,一般用于重定向到完整的URL(包含http:部分)
  因为301和302不能简单的只单纯返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了. 作为替换,rewrite可以更灵活的使用redirect和permanent标志实现301和302. 比如上一篇日志中提到的Blog搬家要做的域名重定向,在nginx中就会这么写
rewrite ^ (.* )$ http://newdomain.com/ permanent;  举例来说一下rewrite的实际应用
  rewrite ^ (/download /. * ) /media / (. * )\.. *$ $1 /mp3 / $2.mp3 last;
  如果请求为 /download/eva/media/op1.mp3 则请求被rewrite到 /download/eva/mp3/op1.mp3
  要注意的是rewrite有很多潜规则需要注意:
  - rewrite的生效区块为sever, location, if
  - rewrite只对相对路径进行匹配,不包含hostname 比如说以上面301重定向的例子说明
rewrite ~ * cafeneko\.info http://newdomain.com / permanent;  这句是永远无法执行的,以这个URL为例
  http://blog.cafeneko.info/2010/10/neokoseseiki_in_new_home/?utm_source=rss&utm_medium=rss&utm_campaign=neokoseseiki_in_new_home
  其中cafeneko.info叫做hostname,再往后到?为止叫做相对路径,?后面的一串叫做query string
  对于rewrite来说,其正则表达式仅对”/2010/10/neokoseseiki_in_new_home”这一部分进行匹配,即不包含hostname,也不包含query string .所以除非相对路径中包含跟域名一样的string,否则是不会匹配的.
  如果非要做域名匹配的话就要使用if语句了,比如进行去www跳转
  if ( $host ~ * ^www\. (cafeneko\.info) ) { set $host_without_www $1; rewrite ^ (. * )$ http: // $host_without_www $1permanent; }
  - 使用相对路径rewrite时,会根据HTTP header中的HOST跟nginx的server_name匹配后进行rewrite,如果HOST不匹配或者没有HOST信息的话则rewrite到server_name设置的第一个域名,如果没有设置server_name的话,会使用本机的localhost进行rewrite
  - 前面提到过,rewrite的正则是不匹配query string的,所以默认情况下,query string是自动追加到rewrite后的地址上的,如果不想自动追加query string,则在rewrite地址的末尾添加?
  rewrite ^ /users/ (. * )$ /show? user= $1? last;
  rewrite的基本知识就是这么多..但还没有完..还有最头疼的部分没有说…
  /2 Nginx location 和 rewrite retry
  nginx的rewrite有个很奇特的特性 — rewrite后的url会再次进行rewrite检查,最多重试10次,10次后还没有终止的话就会返回HTTP 500
  last和break最大的不同在于
  - break是终止当前location的rewrite检测,而且不再进行location匹配
  – last是终止当前location的rewrite检测,但会继续重试location匹配并处理区块中的rewrite规则
  还是这个该死的例子
  location /download/ { rewrite ^ ( /download /. * ) /media / (. * )\.. *$ $1 /mp3 / $2.mp3 ; rewrite ^ ( /download /. * )/movie / (. * )\.. *$ $1 /avi / $2.mp3 ; rewrite ^ ( /download /. * ) /avvvv / (. * )\.. *$ $1 /rmvb / $2.mp3 ; }
  上面没有写标志位,请各位自行脑补…
  如果请求为 /download/acg/moive/UBW.avi
  last的情况是: 在第2行rewrite处终止,并重试location /download..死循环
  break的情况是: 在第2行rewrite处终止,其结果为最终的rewrite地址.
  也就是说,上面的某位试图下载eva op不但没下到反而被HTTP 500射了一脸的例子正是因为用了last标志所以才会造成死循环,如果用break就没事了.
  location /download/ { rewrite ^ ( /download /. * ) /media / (. * )\.. *$ $1 /mp3 / $2.mp3 break; }
  对于这个问题,我个人的建议是,如果是全局性质的rewrite,最好放在server区块中并减少不必要的location区块.location区块中的rewrite要想清楚是用last还是break.
  有些情况是要用last的. 典型的例子就是wordpress的permalink rewrite
  常见的情况下, wordpress的rewrite是放在location /下面,并将请求rewrite到/index.php
  这时如果这里使用break乃就挂了,不信试试. b( ̄▽ ̄)d…因为nginx返回的是没有解释的index.php的源码…
  这里一定要使用last才可以在结束location / 的rewrite, 并再次命中location ~ \.php$,将其交给fastcgi进行解释.其后返回给浏览器的才是解释过的html代码.
  关于nginx rewrite的简介到这里就全部讲完了,水平及其有限,请大家指出错漏…
  
  结合QeePHP的例子
if (!-d $request_filename) {  
    rewrite ^/([a-z-A-Z]+)/([a-z-A-Z]+)/?(.*)$ /index.php?namespace=user&controller=$1&action=$2&$3 last;
  
    rewrite ^/([a-z-A-Z]+)/?$ /index.php?namespace=user&controller=$1 last;
  
    break;
  
}
  多目录转成参数
  abc.domian.com/sort/2 => abc.domian.com/index.php?act=sort&name=abc&id=2
if ($host ~* (.*)\.domain\.com) {  
    set $sub_name $1;
  
    rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&cid=$sub_name&id=$1 last;
  
}
  目录对换
  /123456/xxxx -> /xxxx?id=123456
rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;  例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下:
if ($http_user_agent ~ MSIE) {  
    rewrite ^(.*)$ /nginx-ie/$1 break;
  
}
  目录自动加“/”
if (-d $request_filename){  
    rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
  
}
  禁止htaccess
location ~/\.ht {  
    deny all;
  
}
  禁止多个目录
location ~ ^/(cron|templates)/ {  
    deny all;
  
    break;
  
}
  禁止以/data开头的文件
  可以禁止/data/下多级目录下.log.txt等请求;
location ~ ^/data {  
    deny all;
  
}
  禁止单个目录
  不能禁止.log.txt能请求
location /searchword/cron/ {  
    deny all;
  
}
  禁止单个文件
location ~ /data/sql/data.sql {  
deny all;
  
}
  给favicon.ico和robots.txt设置过期时间;
  这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志
location ~(favicon.ico) {  
    log_not_found off;
  
    expires 99d;
  
    break;
  
}
  
location ~(robots.txt) {
  
    log_not_found off;
  
    expires 7d;
  
    break;
  
}
  设定某个文件的过期时间;这里为600秒,并不记录访问日志
location ^~ /html/scripts/loadhead_1.js {  
    access_log   off;
  
    root /opt/lampp/htdocs/web;
  
    expires 600;
  
    break;
  
}
  文件反盗链并设置过期时间
  这里的return 412 为自定义的http状态码,默认为403,方便找出正确的盗链的请求
  “rewrite ^/ http://leech.divmy.com/leech.gif;”显示一张防盗链图片
  “access_log off;”不记录访问日志,减轻压力
  “expires 3d”所有文件3天的浏览器缓存
location ~* ^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {  
    valid_referers none blocked *.c1gstudio.com *.c1gstudio.net localhost 208.97.167.194;
  
    if ($invalid_referer) {
  
        rewrite ^/ http://leech.divmy.com/leech.gif;
  
        return 412;
  
        break;
  
    }
  
    access_log   off;
  
    root /opt/lampp/htdocs/web;
  
    expires 3d;
  
    break;
  
}
  只充许固定ip访问网站,并加上密码
root  /opt/htdocs/www;  
    allow   208.97.167.194;
  
    allow   222.33.1.2;
  
    allow   231.152.49.4;
  
    deny    all;
  
    auth_basic “C1G_ADMIN”;
  
    auth_basic_user_file htpasswd;
  将多级目录下的文件转成一个文件,增强seo效果
  /job-123-456-789.html 指向/job/123/456/789.html
rewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /job/$1/$2/jobshow_$3.html last;  将根目录下某个文件夹指向2级目录
  如/shanghaijob/ 指向 /area/shanghai/
  如果你将last改成permanent,那么浏览器地址栏显是/location/shanghai/
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;  上面例子有个问题是访问/shanghai 时将不会匹配
rewrite ^/([0-9a-z]+)job$ /area/$1/ last;  
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;
  这样/shanghai 也可以访问了,但页面中的相对链接无法使用,
  如./list_1.html真实地址是/area/shanghia/list_1.html会变成/list_1.html,导至无法访问。
  那我加上自动跳转也是不行咯
  (-d $request_filename)它有个条件是必需为真实目录,而我的rewrite不是的,所以没有效果
if (-d $request_filename){  
    rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
  
}
  知道原因后就好办了,让我手动跳转吧
rewrite ^/([0-9a-z]+)job$ /$1job/ permanent;  
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;
  文件和目录不存在的时候重定向:
if (!-e $request_filename) {  
    proxy_pass http://127.0.0.1;
  
}
  域名跳转
server  
{
  
listen       80;
  
server_name  jump.88dgw.com;
  
index index.html index.htm index.php;
  
root  /opt/lampp/htdocs/www;
  
rewrite ^/ http://www.88dgw.com/;
  
access_log  off;
  
}
  多域名转向
server_name  www.7oom.com/  www.divmy.com/;  
index index.html index.htm index.php;
  
root  /opt/lampp/htdocs;
  
if ($host ~ “c1gstudio\.net”) {
  
    rewrite ^(.*) http://www.7oom.com$1/ permanent;
  
}
  三级域名跳转
if ($http_host ~* “^(.*)\.i\.c1gstudio\.com$”) {  
    rewrite ^(.*) http://top.88dgw.com$1/;
  
    break;
  
}
  域名镜向
server  
{
  
listen       80;
  
server_name  mirror.c1gstudio.com;
  
index index.html index.htm index.php;
  
root  /opt/lampp/htdocs/www;
  
rewrite ^/(.*) http://www.divmy.com/$1 last;
  
access_log  off;
  
}
  某个子目录作镜向
location ^~ /zhaopinhui {  
rewrite ^.+ http://zph.divmy.com/ last;
  
break;
  
}
  discuz ucenter home (uchome) rewrite
rewrite ^/(space|network)-(.+)\.html$ /$1.php?rewrite=$2 last;  
rewrite ^/(space|network)\.html$ /$1.php last;
  
rewrite ^/([0-9]+)$ /space.php?uid=$1 last;
  discuz 7 rewrite
rewrite ^(.*)/archiver/((fid|tid)-[\w\-]+\.html)$ $1/archiver/index.php?$2 last;  
rewrite ^(.*)/forum-([0-9]+)-([0-9]+)\.html$ $1/forumdisplay.php?fid=$2&page=$3 last;
  
rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/viewthread.php?tid=$2&extra=page\%3D$4&page=$3 last;
  
rewrite ^(.*)/profile-(username|uid)-(.+)\.html$ $1/viewpro.php?$2=$3 last;
  
rewrite ^(.*)/space-(username|uid)-(.+)\.html$ $1/space.php?$2=$3 last;
  
rewrite ^(.*)/tag-(.+)\.html$ $1/tag.php?name=$2 last;
  给discuz某版块单独配置域名
server_name  bbs.c1gstudio.com news.c1gstudio.com;  
location = / {
  
if ($http_host ~ news\.divmy.com$) {
  
    rewrite ^.+ http://news.divmy.com/forum-831-1.html last;
  
    break;
  
    }
  
}
  discuz ucenter 头像 rewrite 优化
location ^~ /ucenter {  
location ~ .*\.php?$
  
{
  
#fastcgi_pass  unix:/tmp/php-cgi.sock;
  
fastcgi_pass  127.0.0.1:9000;
  
fastcgi_index index.php;
  
include fcgi.conf;
  
}
  
location /ucenter/data/avatar {
  
log_not_found off;
  
access_log   off;
  
location ~ /(.*)_big\.jpg$ {
  
    error_page 404 /ucenter/images/noavatar_big.gif;
  
}
  
location ~ /(.*)_middle\.jpg$ {
  
    error_page 404 /ucenter/images/noavatar_middle.gif;
  
}
  
location ~ /(.*)_small\.jpg$ {
  
    error_page 404 /ucenter/images/noavatar_small.gif;
  
}
  
expires 300;
  
break;
  
}
  
}
  jspace rewrite
location ~ .*\.php?$  
{
  
#fastcgi_pass  unix:/tmp/php-cgi.sock;
  
fastcgi_pass  127.0.0.1:9000;
  
fastcgi_index index.php;
  
include fcgi.conf;
  
}
  
location ~* ^/index.php/
  
{
  
rewrite ^/index.php/(.*) /index.php?$1 break;
  
fastcgi_pass  127.0.0.1:9000;
  
fastcgi_index index.php;
  
include fcgi.conf;
  
}
  另外这里还有一个工具可以直接把apache规则转化为nginx规则
  http://www.anilcetin.com/convert-apache-htaccess-to-nginx/
  参考:
  http://wiki.nginx.org/NginxChsHttpRewriteModule
  http://blog.csdn.net/cnbird2008/archive/2009/08/04/4409620.aspx
  http://www.divmy.com/



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-633916-1-1.html 上篇帖子: ubuntu安装nginx 下篇帖子: nginx rewrite指令
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表