十二、rewrite规则

一、rewrite规则说明

Nginx rewrite的主要功能也是实现URL地址重写。Nginx的rewrite规则需要PCRE软件的支持,即通过Perl兼容正则表达式语法进行规则匹配。前文在安装Nginx软件时就已经安装了这个PCRE软件,同时也让Nginx支持了rewrite的功能,默认参数编译时,Nginx就会安装支持rewrite的模块,但是,也必须要有PCRE软件的支持。

二、rewrite语法参数

1.rewrite指令语法

指令语法:rewrite regex replacement[flag];
默认值:none
应用位置:server、location、if
rewrite是实现URL重写的关键指令,根据regex(正则表达式)部分的内容,重定向到replacement部分,结尾是flag标记。

如果指定的正则表达式与请求URI匹配,则URI将按照*replacement*字符串中的指定进行更改。该rewrite指令在其在配置文件中出现的顺序顺序地执行。可以使用标志终止指令的进一步处理。如果替换字符串以“ http://”,“ https://”或“ $scheme” 开头,则处理停止,并将重定向返回给客户端。

可选flag参数可以是以下之一:
last: 停止处理当前ngx_http_rewrite_module指令集, 并开始搜索与更改后的URI相匹配的新位置;
break: ngx_http_rewrite_module与break指令一样, 停止处理当前的指令集 ;
redirect: 返回带有302代码的临时重定向;如果替换字符串不是以“ http://”,“ https://”或“ $scheme” 开头,则使用
permanent: 返回带有301代码的永久重定向。

示例1:

用户访问www.ywx.com/image----->www.ywx.com/tupian
也可以当用户访问http://www.ywx.com----->https://www.ywx.com

示例2:

一个简单的URL rewrite跳转的例子:

rewrite ^/(.*) http://www.ywx.org/$1 permanent;
#在上述指令中,rewrite为固定关键字,表示开启一条rewrite匹配规则,regex部分是^/(.*),这是一个正则表达式,表示匹配所有,匹配成功后跳转到http://www.ywx.org/$1。这里的$1是取前面regex部分括号里的内容,结尾的permanent;是永久301重定向标记,即跳转到后面的http://www.ywx.org/$1地址上。

2.regex常用正则表达式说明

rewrite regex replacement [flag]
将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为replacement指定的新的URI
注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查
隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制
如果replacement是以http://或https://开头,则替换结果会直接以重向返回给客户端, 即永久重定向301

正则表达式

 \:后面接着的字符标记未一个特殊字符或一个原义字符或一个后向引用。eg."\n"匹配一个换行符,"\\""\$"则匹配“$”

 ^:匹配输入字符串的起始位置

 $:匹配输入字符串的结束位置

 *:匹配前面的字符0次或多次

 +:匹配前面的字符1次或多次

 ?:匹配前面的字符0次或1次

 .:匹配除"\n"之外的任何单个字符,要匹配“\n”,则使用“[.\n]”

3.rewrite指令结尾的flag标记说明

rewrite指令的最后一项参数为flag标记

last 持续匹配新的uri资源

重写完成后停止对当前URI在当前location中后续的其它重写操作,而后对新的URI启动新一轮重写检查;提前重启新一轮循环

break 匹配到第一个uri资源后就终止

重写完成后停止对当前URI在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块后的其它配置;结束循环
last 和 break的比较

break:匹配成功后不再向下匹配,也不会跳转到其他的location,即直接结束匹配并给客户端返回结果数据
last:对某个location的URL匹配成功后会停止当前location的后续rewrite规则,并结束当前location,然后将匹配生成的新URL跳转至其他location继续匹配,直到没有location可匹配后将最后一次location的数据返回给客户端

示例:

location /break {
  rewrite ^/break/(.*) /test/$1 break; #break不会跳转到其他的location
  return 666 "break";
}
location /last {
  rewrite ^/last/(.*) /test/$1 last; #last会跳转到其他的location继续匹配新的URI
  return 888 "last";
}
location /test {
  return 999 "test";
  index index.html;
  root /data/nginx;
}
mkdir /data/nginx/test/
echo test Page > /data/nginx/test/index.html

redirect 临时跳转到uri资源信息

临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URI给客户端,由客户端重新发起请求;可使用相对路径,或http://或https://开头,此重定向信息不可缓存,状态码:302

permanent 永久跳转

重写完成后以永久重定向方式直接返回重写后生成的新URI给客户端,由客户端重新发起请求,此重定向信息可缓存,状态码:301

在以上的flag标记中,last和break用来实现URL重写,浏览器地址栏的URL地址不变,但在服务器端访问的程序及路径发生了变化。redirect和permanent用来实现URL跳转,浏览器地址栏会显示跳转后的URL地址。

last和break标记的实现功能类似,但二者之间有细微的差别,使用alias指令时必须用last标记,使用proxy_pass指令时要使用break标记。last标记在本条rewrite规则执行完毕后,会对其所在的server{………}标签重新发起请求,而break标记则会在本条规则匹配完成后,终止匹配,不再匹配后面的规则。

示例1:

要求:将 http:// 请求跳转到 https://
生产案例
location / {
  if ($scheme = http ) {
    rewrite / https://www.ywx.com/ redirect;
   }
}

示例2:

要求:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页
生产案例
location / {
  root /data/nginx/html/pc;
  index index.html;
  if (!-f $request_filename) {
  #return 404 "No exsit";
  rewrite (.*) http://www.ywx.com/index.html;
  }
}

4、return code

Syntax:    return code [text];
           return code URL;
           return URL;
Default:    —
Context:    server, location, if

停止处理并将指定的返回*code*给客户端。非标准代码444关闭连接而不发送响应头。

return code [text]; #返回客户端指定的状态码和文本说明
return code URL;
return URL;
停止处理,并返回给客户端指定的响应码(包括: 204, 400, 402406, 408, 410, 411, 413, 416, 500504),并对 301, 302, 303, 307, 308跳转到URL

示例:

location /test {
  index index.html;
  default_type text/html;
  if ( $scheme = http ){
    return 301 https://www.ywx.com;
  }
  if ( $scheme = https ){
    echo "if ----> $scheme";
  }
  
  #当用户访问www.ywx.com/test时:
  #如果使用https://www.ywx.com/test则返回echo信息
  #如果使用http://www.ywx.com/test,返回301code并跳转到https://www.ywx.com/test

5、rewrite_log

Syntax:    rewrite_log on | off;
Default:    rewrite_log off;
Context:    http, server, location, if

是否开启重写日志, 发送至error_log(notice level)

示例:

location /test {
  root /data/nginx/html/pc;
  default_type text/html;
  index index.html;
  if ( $scheme = http ){
    #return 666;
    #return 666 "not allow http";
    #return 301 http://www.baidu.com;
    return 500 "service error";
    echo "if-----> $scheme"; #return后面的将不再执行
  }
  if ( $scheme = https ){
    echo "if ----> $scheme";
  }
}

6、rewrite中的if语句

Syntax:    if (condition) { ... }
Default:    —
Context:    server, location

条件满足时,执行配置块中的配置指令。

condition:常与nginx的内置变量,$scheme,$http_user_agent,$http_cookie,$request_method...配合使用

比较操作符:

1、变量名;如果变量的值为空字符串或“ 0”,则为false;否则为false 。(在1.0.1版之前,任何以“ 0” 开头的字符串都被视为错误值。)
2、使用“ =”和“ !=”运算符将变量与字符串进行比较;
3、使用“ ~”(用于区分大小写的匹配)和“ ~*”(用于不区分大小写的匹配)运算符将变量与正则表达式进行匹配。正则表达式可以包含捕获,这些捕获可用于以后在$1.. $9变量中重用。
4、使用“ !~(区分大小写)”模式不匹配和“ !~*(不区分大小写)”的模式不匹配。如果正则表达式包含“ }”或“ ;”字符,则整个表达式应用单引号或双引号引起来。
5、使用“ -f”和“ !-f”运算符检查文件是否存在;
6、使用“ -d”和“ !-d”运算符检查目录是否存在;
7、使用“ -e”和“ !-e”运算符检查文件,目录或符号链接是否存在;
8、使用“ -x”和“ !-x”运算符检查可执行文件。

示例1:

location /test {
  index index.html;
  default_type text/html;
  if ( $scheme = http ){
    return 301 https://www.ywx.com;
  }
  if ( $scheme = https ){
    echo "if ----> $scheme";
  }
  
  #当用户访问www.ywx.com/test时:
  #如果使用https://www.ywx.com/test则返回echo信息
  #如果使用http://www.ywx.com/test,返回301code并跳转到https://www.ywx.com/test

示例2:

if (-f $request_filename) {
   echo "file is exist";
}
if (!-f $request_filename) {
   echo "file is not exist";
   return 409;
}
#$request_filename文件存在则返回"file is exist";
#$request_filename文件不存在则返回"file is not exist",code代码=409

三、案例

1、Nginx rewrite 301跳转

以往我们是通过别名的方式实现etiantian.org和www.etiantian.org访问同一个地址的,事实上,除了这个方式以外,还可以使用Nginx rewrite 301跳转的方式来实现。实现的配置如下:

 

[root@www extra]# cat www.conf
server {
  listen   80;
  server_name  etiantian.org;
  rewrite ^/(.*) http://www.etiantian.org/$1 permanent;
#<==当用户访问etiantian.org及下面的任意内容时,都会通过这条rewrite跳转www.etiantian.org对应的地址
#如访问etiantian.org/index.html跳转到www.etiantian.org/index.html
 }

#为了避免返回404,应该有ww.etiantian.org的地址
server {
  listen   80;
  server_name  www.etiantian.org;
  location / {
    root   html/www;
    index  index.html index.htm;
  }
  access_log logs/access_www.log main gzip buffer=32k flush=5s;
}

2、实现不同域名的URL跳转

例1:实现访问http://blog.etiantian.org时跳转到http://www.etiantian.org/blog/oldboy.html

外部跳转时使用这种方法,可让浏览器地址变为跳转后的地址,另外,要事先设置http://www.etiantian.org/blog/oldboy.html有结果输出,不然会出现401等权限错误。

1.配置Nginx rewrite规则

跳转前,http://blog.etiantian.org对应站点的配置如下:

[root@www extra]# cat blog.conf
server {
  listen   80;
  server_name  blog.etiantian.org;
  location / {
    root   html/blog;
    index  index.html index.htm;
  }
  if ( $http_host ~* "^(.*)\.etiantian\.org$") { 
    set $domain $1; 
    rewrite ^(.*) http://www.etiantian.org/$domain/oldboy.html break; 
  } 
}

要配置的规则内容为:

if ( $http_host ~* "^(.*)\.etiantian\.org$") { 
 set $domain $1; 
 rewrite ^(.*) http://www.etiantian.org/$domain/oldboy.html break; 
}

跳转后,http://www.etiantian.org/blog/oldboy.html地址对应的站点配置如下:

[root@www extra]# cat www.conf
server {
  listen   80;
  server_name  www.etiantian.org etiantian.org;
  location / {
    root   html/www;
    index  index.html index.htm;
  }
  access_log logs/access_www.log main gzip buffer=32k flush=5s;
}

例2:实现访问http://etiantian.org/bbs时跳转到http://bbs.etiantian.org

在etiantian.org下设置Nginx rewrite规则,如下:

[root@www extra]# cat www.conf
server {
  listen   80;
  server_name  www.etiantian.org etiantian.org;
  location / {
    root   html/www;
    index  index.html index.htm;
  }
  rewrite ^(.*)/bbs/  http://bbs.etiantian.org break;
  access_log logs/access_www.log main gzip buffer=32k flush=5s;
}

配置bbs.etiantian.org的站点内容

[root@www extra]# cat bbs.conf
server {
  listen   80;
  server_name  bbs.etiantian.org;
  location / {
    root   html/bbs;
    index  index.html index.htm;
  }
}

在根location(即location/{……})中或server{……}标签中编写rewrite规则,建议使用last标记,而在普通的location(例location/oldboy/{……}或if{})中编写rewrite规则,则建议使用break标记。

例3:实现域名地址信息跳转

用于做伪静态

www.etiantian.org/oldboy?edu.html ---动态资源

www.etiantian.org/oldboy-edu.html ---伪静态

实现类似百度重写域名的功能?

baidu.com ===> www.baidu.com

etiantian.org ===> www.etiantian.org

rewrite指令实践操作一:(错误)

[root@web01 extra]# cat bbs.conf 
server {
  listen 80;
  server_name www.etiantian.org bbs.org;
  rewrite ^/(.*) http://www.etiantian.org/$1 permanent; ----此处用到了perl语言的正则表达式
  root html/bbs;
  index index.html index.htm;
}

[root@web01 extra]# curl -L etiantian.org 
curl: (47) Maximum (50) redirects followed
[root@web01 extra]# curl -Lv etiantian.org --- 显示无限循环过程

说明:以上配置进入了无限循环状态

rewrite指令实践操作二:(正确)

cat bbs.conf 
server {
  listen 80;
  server_name etiantian.org;
  rewrite ^/(.*) http://bbs.etiantian.org/$1 permanent;
}
server {
  listen 80;
  server_name bbs.etiantian.org bbs.org;
  root html/bbs;
  index index.html index.htm;
}

rewrite指令实践操作三:(正确)

[root@web01 extra]# cat bbs.conf 
server {
  listen 80;
  server_name bbs.etiantian.org bbs.org;
  if ($host ~ "^etiantian.org$") {
  rewrite ^/(.*) http://bbs.etiantian.org/$1 permanent;
  }
  root html/bbs;
  index index.html index.htm;
}

访问bbs.ywx.com跳转到www.ywx.com/bbs/ywx.html 首先要www.ywx.com/bbs/ywx.html的内容可以被访问

server {
   listen 80;
   server_name   www.ywx.com;
   root   html/www;
   index  index.html index.htm;
   if ( $http_host ~* "^bbs\.ywx\.com$" ) {

   rewrite ^(.*) http://www.ywx.com/bbs/ywx.html break;

   }
}

或者

server{
   listen 80;
   server_name  bbs.ywx.com;
   rewrite  ^(.*) http://www.ywx.com/bbs/ywx.html
}  
server {
   listen  80;
   server_name   www.ywx.com;
   root   html/www;
   index  index.html index.htm;      
}

3、客户访问http请求,则跳转https://10.0.0.101;客户访问的页面不存在,则跳转到https://10.0.0.101

nginx安装部署略过

nginx的server的配置

 server {
        server_name  localhost;
        listen 443 ssl;
        ssl_certificate /etc/pki/CA/certs/nginx.crt;
        ssl_certificate_key /data/nginx.key;
        ssl_session_cache shared:sslcache:20m;
        ssl_session_timeout 10m;
        location / {
            root   html;
            index  index.html index.htm;
            default_type test/html;
        }
    
 }

  server {
        server_name  localhost;
        listen 80;
        location / {
            root   html;
            index  index.html index.htm;
            default_type test/html;
            if ( $scheme = http ){
                return 301 https://10.0.0.101;
            }
            if ( $scheme = https ){
                echo "if ----> $scheme";
            }
           if ( !-f $request_filename ) {
                rewrite (.*) https://10.0.0.101;
            }
        }

   }

重新加载配置文件

nginx -t
nginx -s reload

测试访问

在非nginx服务器上,我是在在10.0.0.102上访问

[root@node2 ~]# curl http://10.0.0.101:80
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.16.0</center>
</body>
</html>
#301跳转

[root@node2 ~]# curl -L http://10.0.0.101:80
curl: (60) Peer's Certificate issuer is not recognized.
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
#跳转到https

[root@node2 ~]# curl -Lk http://10.0.0.101:80
ni hao nginx!!!
访问http自动跳转为https


访问一个不存在的页面
[root@node2 ~]# curl http://10.0.0.101:80/kkkkkkkkkkkkk
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.16.0</center>
</body>
</html>
[root@node2 ~]# curl -L http://10.0.0.101:80/kkkkkkkkkkkkk
curl: (60) Peer's Certificate issuer is not recognized.
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
[root@node2 ~]# curl -Lk http://10.0.0.101:80/kkkkkkkkkkkkk
ni hao nginx!!!
#最后会跳转到https://10.0.0.101

 

posted @ 2020-09-12 11:33  yaowx  阅读(987)  评论(0编辑  收藏  举报