Nginx中的Location和Rewrite

Nginx中的Location和Rewrite

一、location

1. location的分类

location大致可以分为三类:

  1. 精准匹配:location = /
  2. 一般匹配:location /
  3. 正则匹配:location ~ /

2. location常用的匹配规则

匹配规则 说明
= 进行普通字符精确匹配,也就是完全匹配
^~ 表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他location
~ 区分大小写的匹配
~* 不区分大小写的匹配
!~ 区分大小写的匹配取非
!~* 不区分大小写的匹配取非

3. location优先级

  1. 精确匹配 =
  2. 前缀匹配 ^~
  3. 按文件中的顺序的正则匹配 /~ 或 ~/*
  4. 匹配不带任何修饰的一般前缀匹配
  5. /通用匹配

总结:
(location = 完整路径) > (location ^~ 路径) > (location ~[*] 正则顺序) > (location 部分起始路径)> (location /)

4. location的示例说明

  1. location = / {}
    =为精确匹配 / ,主机名后面不能带任何字符串,比如访问 / 和/data,则 / 匹配,/data不匹配。
    再比如 location = /abc ,则只匹配/abc,/abc/或/abcd不匹配;
    若 location /abc ,则即匹配/abc、/abcd/同时也匹配/abc/。
  2. location / {}
    因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求,比如访问 / 和 /data,则 / 匹配,/data也匹配;
    但若后面是正则表达式会和最长字符串优先匹配(最长匹配)。
  3. location /documents/ {}
    匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索其它location,只有其它location后面的正则表达式没有匹配到时,才会采用这一条。
  4. location /documents/abc {}
    匹配任何以 /documents/abc 开头的地址,匹配符合以后,还要继续往下搜索其它location,只有其它location后面的正则表达式没有匹配到时,才会采用这一条。
  5. location ^~ /images/ {}
    匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
  6. location ~* .(gif|jpg|jpeg)$ {}
    匹配所有以gif/jpg/jpeg结尾的请求。
    然后,所有请求 /images/ 下的图片会被 location ^~ /images/处理,因为 ^~ 的优先级更高,所以到达不了这一条正则。
  7. location /images/abc {}
    最长字符匹配到 /images/abc,优先级最低,继续往下搜索其它location,会发现 ^~ 和 ~ 存在。
  8. location ~ /images/abc {}
    匹配以/images/abc开头的,优先级次之,只有去掉location ^~ /images/ 才会采用这一条。
  9. location /images/abc/1.html {}
    匹配/images/abc/1.html文件,如果和正则location ~ /images/abc/1,html 相比,正则优先级更高。

5. 必选规则

实际网站使用中,至少有三个匹配规则定义

  1. 匹配根
    直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,比如说官网。
    可以是一个静态首页,也可以直接转发给后端应用服务器。
location = / {
    root   html;
    index  index.html index.htm;
}
  1. 处理静态文件请求
    这是nginx作为http服务器的强项。
    有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用。
location ^~ /static/ {
    root /webroot/static/;
}
 
location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ {
    root /webroot/res/;
}
  1. 通用规则
    比如用来转发带.php/.jsp后缀的动态请求到后端应用服务器,非静态文件请求就默认是动态请求。
location / {
    proxy_pass http://tomcat_server;
}

二、Nginx Rewrite

1. Rewrite概述

rewrite功能就是使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标记位实现URL重写以及重定向。
比如:更换域名后需要保持旧的域名能跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求。

2. Rewrite的跳转场景

  1. 调整用户浏览的URL,看起来更规范,合乎开发及产品人员的需求。
  2. 为了让搜索引擎搜录网站内容及用户体验更好,企业会将动态URL地址伪装成静态地址提供服务。
  3. 网址换新域名后,让旧的访问跳转到新的域名商。例如,访问京东的360buy.com会跳转到jd.com。
  4. 服务端某些业务调整,比如根据特殊变量、目录、客户端的信息进行URL调整等。
  5. 网站防盗链的配置部署,防止图片、视频等文件的白嫖、盗用。

3. Rewrite跳转的实现

img
rewrite使用Nginx全局变量或自己设置的变量,结合正则表达式和标志位实现URL重写以及重定向

4. Rewrite的实际场景

  1. nginx跳转需求的实现方式
    使用rewrite进行匹配跳转
    使用if匹配全局变量后跳转
    使用location匹配再跳转
  2. rewrite放在server{}、if{}、location{}段中
    location只对域名后边的除去传递参数外的字符串起作用
  3. 对域名或参数字符串
    使用if全局变量匹配
    使用proxy_pass反向代理

5. Rewrite和local的区别

从功能看rewrite和location似乎有点像,都能实现跳转。
主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,还可以proxy——pass到其他机器。

6. 常用的Nginx正则表达式

正则表达式 说明
^ 匹配输入字符串的起始位置
$ 匹配输入字符串的结束位置
* 匹配前面的字符零次或多次
+ 匹配前面的字符一次或多次
? 匹配前面的字符零次或一次
. 匹配除"\n"之外的任何单个字符,若要匹配包括"\n"在内的任意字符,可使用"[.\n]"
/ 将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用。如"\n"匹配一个换行符,而“\(”则匹配“\)
\d 匹配纯数字
重复n次
重复n次或更多次
重复n到m次
[] 定义匹配的字符范围
[c] 匹配a-z小写字母的任意一个
[a-z] 匹配a-z小写字母的任意一个
[a-zA-Z0-9] 匹配所有大小写字母或数字
() 表达式的开始和结束位置
| 或运算符

7. Rewrite的执行顺序

  1. 执行server块里面的rewrite指令。
  2. 执行location匹配。
  3. 执行选定的location中的rewrite指令。

8. Rewrite的语法格式

rewrite [flag];
regex:表示正则匹配规则。
replacement:表示跳转后的内容。
flag:表示rewrite支持的flag标记。

9. flag的标记说明

falg标记 说明
last 本条规则匹配完成后,继续向下匹配新的location URL规则,一般用在server和if中。
break 本条规则匹配完成即终止,不再匹配后面的任何规则,一般使用在location中
redirect 返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent 返回301永久重定向,浏览器地址栏会显示跳转后的URL地址

10. Rewrite示例

  1. 基于域名的跳转
    测试场景:现在公司旧域名www.old.com有业务需求变更,需要使用新域名www.new.com,但是旧域名不能废除,需要跳转到新域名上,而且后面的参数保持不变。
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
 
    server {
        listen       80;
        server_name  www.old.com;
        #修改域名
        charset utf-8;
        access_log  /var/log/nginx/old.access.log;
        #修改日志保存路径
 
        location / {
        #添加域名重定向
            if($host = 'www.old.com') {
            #$host为rewrite全局变量,代表请求主机头字段或主机名
                rewrite ^/(.*)$ http://www.new.com/$1 permanent;
                #$1为正则匹配的内容,即“域名/”之后的字符串
            }
            root   html;
            index  index.html index.htm;
        }
    }
 
[root@localhost ~]# echo "192.168.122.10 www.old.com www.new.com" >> /etc/hosts
[root@localhost ~]# systemctl restart nginx

测试:浏览器输入模拟访问http://www.old.com/test/1.html(虽然这个请求内容是不存在的)会跳转到www.new.com/test/1.html,查看元素可以看到返回301,实现了永久重定向跳转,而且域名后的参数也正常跳转。

  1. 基于客户端IP访问跳转
    测试场景:今天公司业务新版本上线,要求所有IP访问任务内容都显示一个固定维护页面,只有公司IP:192.168.122.10访问正常。
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
 
    server {
        listen       80;
        server_name  www.test.com;
        #修改域名
        charset utf-8;
        access_log  /var/log/nginx/test.access.log;
        #修改日志保存路径
 
        #设置是否合法的IP标记
        set $rewrite true;
        #设置变量$rewrite,变量值为boole值ture
        #判断是否为合法IP
        if ($remote_addr ="192.168.122.10") {
            set $rewrite false;
        #当客户端为192.168.122.10时,将变量值设为false,不进行重写
        }
 
        #除了合法IP,其他都是非法IP,进行重写跳转维护页面
        if ($rewrite = true) {
        #当变量值为true时,进行重写
            rewrite (.+) /weihu.html;
            #将域名后边的路径重写成/weihu.html,例如www.test.com/weihu.html
        }
 
        location  = /weihu/html {
            root  /var/www/html;
        #网页返回/var/www/html/weihu.html的内容
        }
 
        location / {
            root   html;
            index  index.html index.htm;
        }
    }
 
[root@localhost ~]# mkdir -p /var/www/html/
[root@localhost ~]# echo "<h1>We are maintaining now,please wait!</h1>" > /var/www/html/weihu.html
[root@localhost ~]# systemctl restart nginx

测试:只有IP为192.168.122.10能正常访问,其他地址都是维护页面

注:如果rewrite (.+) /weihu.html;改成rewrite (.+) /weihu.html permanent;的话如果是非192.168.122.10的主机访问会使浏览器修改请求访问的URL成http://www.test.com/weihu.html再请求访问,这样就会进入一直在rewrite的死循环,访问请求会一直重写成http://www.test.com/weihu.html再请求访问。

  1. 基于旧域名跳转到新域名后面加目录
    测试场景:现在访问的是http://bbs.test.com/post/,现在需要将这个域名下面的访问都跳转到http://www.test.com/bbs/post/
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
 
server {
    listen       80;
    server_name  bbs.test.com;
    #修改域名
    charset utf-8;
    #添加
    location /post {
        rewrite (.+) http://www.test.com/bbs$1 permanent;
        #这里的$1为位置变量,代表/post
    }
 
    location / {
        root   html;
        index  index.html index.htm;
    }
}
 
[root@localhost ~]# mkdir -p /usr/local/nginx/html/bbs/post
[root@localhost ~]# echo "this is 1.html" >> /usr/local/nginx/html/bbs/post/1.html
[root@localhost ~]# echo "192.168.80.10 bbs.test.com" >> /etc/hosts
[root@localhost ~]# systemctl restart nginx

测试:使用浏览器访问http://bbs.test.com/post/1.html跳转到http://www.test.com/bbs/post/1.html

  1. 基于参数匹配的跳转
    测试场景:现在访问http://www.test.com/100-(100|200)-100.html跳转到http://www.test.com页面。
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
 
server {
    listen       80;
    server_name  www.test.com;
    #修改域名
    charset utf-8;
    access_log  /var/log/nginx/www.test.com-access.log;
 
    if ($request_uri ~ ^/100-(100-200)-(\d+).html$) {
        rewrite (.+) http://www.test.com permanent;
    }
 
    location / {
        root   html;
        index  index.html index.htm;
    }
}
 
[root@localhost ~]# systemctl restart nginx

\(request_uri:包含请求参照的原因URI,不包含主机名,如:http://www.test.com/abc/bbs/index.html?a=1&b=2中的/abc/bbs/index.php?a=1&b=2 \)uri:这个变量指当前的请求URI,不包括任何参数,如:/abc/bbs/index.html
\(document_uri:与\)uri相同,这个变量指当前的请求URI,不包含任务传递参数,如:/abc/bbs/index.html

测试:使用浏览器访问http://www.test.com/100-200-100.html或http://www.test.com/100-100-100.html跳转到http://www.test.com页面。

  1. 基于目录下所有php结尾的文件跳转
    测试场景:要求访问http://www.test.com/upload/123.php
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
 
server {
    listen       80;
    server_name  www.test.com;
    #修改域名
    charset utf-8;
    access_log   /var/log/nginx/www.test.com-access.log;
    
    location ~* /upload/.*\.php$ {
        rewrite (.+) http://www.test.com permanent;
    }
    
    location / {
        root   html;
        index  index.html index.htm;
    }
}
 
[root@localhost ~]# systemctl restart nginx

测试:浏览器访问http://www.test.com/upload/123.php跳转到http://www.test.com页面。

  1. 基于最普通一条url请求的跳转
    要求访问一个具体的页面如http://www.test.com/abc/123.html跳转到首页
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
 
    listen       80;
    server_name  www.test.com;
    #修改域名
    charset utf-8;
    access_log  /var/log/nginx/www.test.com-access.log;
 
    location / {
        root   html;
        index  index.html index.htm;
    }
}
 
[root@localhost ~]# systemctl restart nginx

浏览器访问http://www.test.com/abc/123.html跳转到http://www.test.com页面。

posted @ 2022-09-02 14:25  玖拾一  阅读(170)  评论(0编辑  收藏  举报