nginx rewrite

nginx rewrite

Nginx工作原理

nginx由内核和模块组成

模块由结构分为:

核心模块: HTTP 模块、EVENT 模块和 MAIL 模块

基础模块: HTTP Access 模块、HTTP FastCGI 模块、HTTP Proxy 模块和 HTTP Rewrite 模块

第三方模块: HTTP Upstream Request Hash 模块、Notice 模块和 HTTP Access Key 模块

由功能分为:

Handlers(处理器模块): 此类模块直接处理请求,并进行输出内容和修改 headers 信息等操作。Handlers 处理器模块一般只能有一个

Filters(过滤器模块):此类模块主要对其他处理器模块输出的内容进行修改操作,最后由 Nginx 输出

Proxies(代理类模块): 此类模块是 Nginx 的 HTTP Upstream 之类的模块,这些模块主要与后端一些服务比如FastCGI 等进行交互,实现服务代理和负载均衡等功能。

Rewrite模块

NGX http rewrite_module官方文档

ngx_http_rewrite_module模块用于使用PCRE正则表达式更改请求URI,返回页面重定向,和按条件选择配置。

ngx_http_rewrite_module模块指令按以下顺序处理:

  • 处理在server级别中定义的模块指令;
  • 为请求查找location;
  • 处理在选中的location中定义的模块指令。如果指令改变了URI,按新的URI查找location。这个循环至多重复10次,之后nginx返回错误500 (Internal Server Error)。

语法:

语法:**rewrite** *regex* *replacement* [*flag*];
默认值:—

上下文:server, location, if

如果指定的正则表达式能匹配URI,此URI将被*replacement*参数定义的字符串改写。

rewrite指令按其在配置文件中出现的顺序执行。flag可以终止后续指令的执行。

如果replacement的字符串以“http://”或“https://”开头,nginx将结束执行过程,并返回给客户端一个重定向。

例如:

语法:rewrite regex replacement flag;,如:

rewrite ^/images/(.*\.jpg)$ /imgs/$1 break;

此处的$1用于引用(.*.jpg)匹配到的内容,又如:

rewrite ^/bbs/(.*)$ http://www.idfsoft.com/index.html redirect;

如上例所示,replacement可以是某个路径,也可以是某个URL

可选的*flag*参数:

flag 作用
last 基本上都用这个flag,表示当前的匹配结束,继续下一个匹配,最多匹配10个到20个 一旦此rewrite规则重写完成后,就不再被后面其它的rewrite规则进行处理 而是由UserAgent重新对重写后的URL再一次发起请求,并从头开始执行类似的过程
break 中止Rewrite,不再继续匹配 一旦此rewrite规则重写完成后,由UserAgent对新的URL重新发起请求, 且不再会被当前location内的任何rewrite规则所检查
redirect 以临时重定向的HTTP状态302返回新的URL
permanent 以永久重定向的HTTP状态301返回新的URL

rewrite模块的作用是用来执行URL重定向。这个机制有利于去掉恶意访问的url,也有利于搜索引擎优化(SEO)

nginx使用的语法源于Perl兼容正则表达式(PCRE)库,基本语法如下:

标识符 意义
^ 必须以^后的实体开头
$ 必须以$前的实体结尾
. 匹配任意字符
[] 匹配指定字符集内的任意字符
[^] 匹配任何不包括在指定字符集内的任意字符串
| 匹配 | 之前或之后的实体
() 分组,组成一组用于匹配的实体,通常会有 | 来协助

捕获子表达式,可以捕获放在()之间的任何文本,比如:

^(hello|sir)$       //字符串为“hi sir”捕获的结果:$1=hi$2=sir

//这些被捕获的数据,在后面就可以当变量一样使用了

模块应用场景:

地址跳转,例如换新域名后,让旧域名跳转到新域名上

协议跳转,用户通过http协议请求网站时,将其重新跳转至https协议方式

伪静态,很多企业会将动态URL地址伪装成静态地址提供服务,减少过多的参数暴露

搜索引擎,SEO优化依赖于url路径,好记的url便于智齿搜索引擎录入

企业会将动态URL地址伪装成静态地址提供服务

网址换新域名后,让旧的访问跳转到新的域名.上

服务端某些业务调整

实例

#nginx的默认根目录下的images目录没有数据,而/opt/imgs下有名字加1.jpg的图片
[root@www ~]# ls /usr/local/nginx/html/images/
[root@www ~]# ls /opt/imgs/
1.jpg

#当访问images下以.jpg结尾的文件时转到/opt/imgs下的.jpg文件

......
        location / {
            root   html;
            index  index.html index.htm;
        }
		location /images {
            root    /opt;
            rewrite ^/images/(.*\.jpg)$ /imgs/$1 break;
        }
......


URI是/images/1.jpg,而/images下是没有数据的,说明确实跳转到了/opt/imgs/1.jpg

也可以用last这样写

[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
......
        location / {
            root   html;
            index  index.html index.htm;
        }
        location /images {
            rewrite ^/images/(.*\.jpg)$ /imgs/$1 last;
        }
        location /imgs {
            root /opt;
        }
[root@www ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@www ~]# nginx -s reload
......

一样可以访问,这里在处理last之前的指令集时,会停止处理后续rewrite指令集,跳出当前的location作用域,并开始搜索与更改后的URI相匹配的location,同时URL地址是不变的

if

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

计算指定的condition的值。如果为真,执行定义在大括号中的rewrite模块指令,并将if指令中的配置指定给请求。if指令会从上一层配置中继承配置。

条件可以是下列任意一种:

  • 变量名;如果变量值为空或者是以“0”开始的字符串,则条件为假;
  • 使用“=”和“!=”运算符比较变量和字符串;
  • 使用“~”和“~*” (区分大小写和不区分大小写)运算符匹配变量和正则表达式。正则表达式可以包含匹配组,匹配结果后续可以使用变量$1..$9引用。如果正则表达式中包含字符“}”或者“;”,整个表达式应该被包含在单引号或双引号的引用中。
  • 使用“-f”和“!-f”运算符检查文件是否存在;
  • 使用“-d”和“!-d”运算符检查目录是否存在;
  • 使用“-e”和“!-e”运算符检查文件、目录或符号链接是否存在;
  • 使用“-x”和“!-x”运算符检查可执行文件;

nginx一些内置变量

变量名 说明
$arg_name 指URL请求中的参数,name是参数的名字
$args 代表URL中所有请求的参数
$binary_remote_addr 客户端地址以二进制数据的形式出现,通常会和限速模块一起使用
$body_bytes_sent 发送给客户端的字节数,不包含响应头
$bytes_set 发送给客户端的字节总数
$document_uri 设置$uri的别名
$hostname 运行Nginx的服务器名
$http_referer 表示请求是从哪个页面链接过来的
$http_user_agent 客户端浏览器的相关信息
$remote_addt 客户端IP地址
$remote_port 客户端端口号
$remote_user 客户端用户名,通常在Auth Basic模块中使用
$request_filename 请求的文件路径,基于root alias指令和URI请求生成
$request_time 请求被nginx接收后,一直到相应数据返回给客户端所用时间
$request_uri 请求的URI,带参数
$request 记录请求的URL和HTTP
$request_length 请求的长度,包括请求行、请求头和请求正文
$server_name 虚拟主机的server_name的值,通常是域名
$server_port 服务器端口号
$server_addr 服务器的IP地址
$request_method 请求的方式,如GET、POST
$scheme 请求的协议,如HTTP、HTTPS
$sent_http_name 任意响应头,name为响应头的名字,注意name要小写
$realip_remote_addr 保留原来的客户地址,在real_ip模块中使用
$server_protocol 请求采用的协议名称和版本号,常为HTTP/1.0或HTTP1.1
$uri 当前请求的URI,在请求过程中URI可能会改变,例如在内部重定向或使用索引文件时
$nginx_version Nginx版本号
$pid worker进程的PID
$pipe 如果请求是HTTP流水线发送的,pipe值为“p”,否则为“.”
$connection_request 当前通过一个连接获得的请求数量
$cookie_name name即Cookie名字,可得到Cookie信息
$status HTTP请求状态
$msec 日志写入时间。单位为秒,经度为毫秒
$time_local 在通用日志格式下的本地时间
$upstream_addr 请求反向代理到后端服务器的IP地址
$upstream_port 请求反向代理到后端服务器的端口号
$upstream_response_time 请求在后端服务器消耗的时间
$upstream_status 请求在后端你服务器的HTTP响应状态
$geoip_city 城市名称,在geoip模块中使用

基于浏览器实现分离案例

[root@www ~]# mkdir /usr/local/nginx/html/{QQBrowse,Edg,Chrome}
[root@www ~]# echo 'QQBrowse test page..........' > /usr/local/nginx/html/QQBrowser/index.html
[root@www ~]# echo 'EdgBrowser test page..........' > /usr/local/nginx/html/Edg/index.html
[root@www ~]# echo 'ChromeBrowser test page..........' > /usr/local/nginx/html/Chrome/index.html



[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
......
        location / {


            if ($http_user_agent ~ Edg) {
                rewrite ^(.*)$ /Edg/$1 break;
            }

            if ($http_user_agent ~ Chrome) {
                rewrite ^(.*)$ /Chrome/$1 break;
            }

            root   html;
            index  index.html index.htm;
        }


        location /Edg {
            root   html;
            index  index.html;
        }
        location /Chrome {
            root   html;
            index  index.html;
        }
 


......

[root@www ~]# nginx -s reload

谷歌浏览器访问

微软浏览器访问

防盗链案例

如果来源不是www.test.com的就返回403

location ~* \.(jpg|gif|jpeg|png)$ {
  valid_referers none blocked server_names www.test.com;
  if ($invalid_referer) {
    return 403;
    #rewrite ^/ http://www.test.com/403.html;
  }
}

1、none

"Referer" 来源头部为空的情况

2、blocked

"Referer"来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头.

3、server_names

"Referer"来源头部包含当前的server_names(当前域名)

posted @ 2020-08-13 09:23  EverEternity  阅读(177)  评论(0编辑  收藏  举报