4.Nginx Rewrite 相关功能

本文最后更新于:2023年12月5日 晚上

rewrite 是 nginx 服务器的重要功能之一,用于实现 URL 的重写,URL 的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问,另外还可以在一定程度上提高网站的安全性

基于 ngx_http_rewrite_module 模块解析和处理 rewrite 请求,依赖 PCRE,因此编译之前要先安装 PCRE 库

ngx_http_rewrite_module 模块指令

ngx_http_rewrite_module 模块指令:if、set、break、return、rewrite、rewrite_log

下文统称为 rewrite 指令集

if 指令

条件判断,根据判断结果选择不同的 nginx 配置,可以配置在 server 或 location 块中,只能做单次判断,不支持使用 if else 这样的多重判断

if (condition) {...}

使用正则表达式对变量进行匹配,匹配成功时条件为 true,否则为 fasle,变量与表达式之间使用以下符号链接:

=     # 变量和字符串比较,相等为true
!=    # 变量和字符串比较,不相等为true
~    # 通过正则表达式匹配,满足匹配条件为真,区分大小写
!~    # 通过正则表达式匹配,不满足匹配条件为真,区分大小写

~*    # 通过正则表达式匹配,满足匹配条件为真,不区分大小写
!~*    # 通过正则表达式匹配,不满足匹配条件为真,不区分大小写

-f 和 !-f  # 判断请求的文件是否存在
-f 和 !-d  # 判断请求的目录是否存在
-x 和 ! -x  # 判断文件是否可执行
-e 和 !-e  # 判断请求的文件或目录是否存在(包括文件,目录,软链接)

# 注意:
# 变量值为空字符或者0为false,其他情况为true
# nginx1.0.1版本之前,变量值不能以0开头则为false,例如 $var=0xxx 返回false

示例:

location /main {
    index index.html;
    default_type text/html;
    if ( $scheme = http ){
        echo "if-----> $scheme";
    }
    if ( $scheme = https ){
        echo "if ----> $scheme";
    }
    #if (-f $request_filename) {
    # echo "$request_filename is exist";
    #}
    if (!-e $request_filename) {
        echo "$request_filename is not exist";
        #return 409;
    }
}

set 指令

变量赋值:set $var value,value 可以是字符串,可以是变量,也可以是两者结合

范例:

location /main {
    root /data/nginx/html/pc;
    index index.html;
    default_type text/html;
    set $name magedu;
    echo $name;
    set $my_port $server_port;
    echo $my_port;
}

break 指令

break 用于 server、location、if

break 的作用是中断重定向,具体表现就是:

  • server 或 if 中使用 break:break 后面的 rewrite 指令集全部失效,注意 location 不属于 rewrite 指令集,location 之外的 break 影响不到 location 内的指令
  • location 中使用 break:不影响此 location 中后面的所有指令,一般搭配 rewrite 指令使用,直接将重定向的结果返回给客户端

break 和 last

两者通常都搭配 rewrite 指令使用,区别在于:

break 不会再去匹配其他 location,而是直接将重定向的结果返回给客户端,而 last 则继续重定,返回最后一个 location 的匹配结果给客户端

示例 1:break

location /last {
 root /data/nginx; # 这里只能用root,alias不能和rewrite搭配
 index index.html;
    # /data/nginx/last重定向到/data/nginx/test1,将/data/nginx/test1中的内容返回给客户端
 rewrite ^/last/(.*) /test1/$1 break;
}

示例 2:last

location /test1 {
    default_type text/html;
    return 200 "test1";   # 最终返回客户端的结果
}
location /last {
    rewrite ^/last/(.*) /test1/$1 last; # 重定向到location /test1
}

return 指令

完成对请求的处理,直接向客户端返回响应状态码,return 后面的所有指令都不被执行

语法: return code [text];
return code URL;
return URL;
默认值: —
上下文: server, location, if

rewrite_log 指令

设置是否记录 ngx_http_rewrite_module 模块日志记录到 error_log 日志文件当中

语法: rewrite_log on | off;
默认值: rewrite_log off;
上下文: http, server, location, if

rewrite 指令

通过正则表达式的匹配来改变 URI,可以同时存在一个或多个指令,按照顺序依次对 URI 进行匹配,rewrite 主要是针对用户请求的 URL 或者是 URI 做具体处理

语法: rewrite regex replacement [flag];
默认值: —
上下文: server, location, if

注意:如果在同一级配置块中存在多个 rewrite 规则,那么会自上而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过 10 次;如果超过,提示 500 响应码,[flag]所表示的标志位用于控制此循环机制

要注意避免出现超过十次以及 URL 重写后返回错误的给用户

如果替换后的 URL 是以 http://或 https://开头,则替换结果会直接以重定向返回给客户端, 即永久重定向 301

302:浏览器不会缓存当前域名的解析记录
301:浏览器会缓存永久重定向的 DNS 解析记录

flag

rewrtie 有四种不同的 flag,分别是 redirect(临时重定向 302)、permanent(永久重定向 301)、break 和 last。其中前两种是跳转型的 flag,后两种是代理型

  • 跳转型指由客户端浏览器重新对新地址进行请求
  • 代理型是在 WEB 服务器内部实现跳转

正则表达式

.    # 匹配除换行符以外的任意字符
\w    # 匹配字母或数字或下划线或汉字
\s    # 匹配任意的空白符
\d    # 匹配数字
\b    # 匹配单词的开始或结束
^    # 匹配字付串的开始
$    # 匹配字符串的结束
*    # 匹配重复零次或更多次
+    # 匹配重复一次或更多次
?    # 匹配重复零次或一次
(n)   # 匹配重复n次
{n,}   # 匹配重复n次或更多次
{n,m}   # 匹配重复n到m次
*?    # 匹配重复任意次,但尽可能少重复
+?    # 匹配重复1次或更多次,但尽可能少重复
??    # 匹配重复0次或1次,但尽可能少重复
{n,m}?   # 匹配重复n到m次,但尽可能少重复
{n,}?   # 匹配重复n次以上,但尽可能少重复
\W    # 匹配任意不是字母,数字,下划线,汉字的字符
\S    # 匹配任意不是空白符的字符
\D    # 匹配任意非数字的字符
\B    # 匹配不是单词开头或结束的位置
[^x]   # 匹配除了x以外的任意字符
[^magedu]  # 匹配除了magedu 这几个字母以外的任意字符

案例:自动跳转 https

if ($scheme = http ){       # 如果没有加条件判断,会导致死循环
 rewrite / https://$host redirect;
}

案例:判断文件是否存在

if (!-e $request_filename) {
 rewrite .* http://www.magedu.org/index.html;  # 实现客户端浏览器的302跳转
 #rewrite .* /index.html;  # web服务器内部跳转
}

防盗链

防盗链基于客户端携带的 referer 实现,referer 是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer 就是之前的那个网站域名,正常的 referer 信息有以下几种

none # 请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息
blocked # 请求报文有referer首部,但无有效值,比如为空
server_names # referer首部中包含本主机名即nginx监听的server_name
arbitrary_string # 自定义指定字符串,但可使用\*作通配符。示例: \*.magedu.org www.magedu.\*
regular expression # 被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:~.*\.magedu\.com

实现防盗链

基于访问安全考虑,nginx 支持通过 ngx_http_referer_module 模块,检查访问请求的 referer 信息是否有效实现防盗链功能

location /images {
    alias /data/images/;
    valid_referers none blocked server_names lujinkai.cn ~\.baidu\.;    #定义有效的referer
    if ($invalid_referer) {
        return 403;
    }
}

Referer 请求头为指定值时,内嵌变量$invalid_referer 被设置为空字符串, 否则这个变量会被置成“1”。查找匹配时不区分大小写


4.Nginx Rewrite 相关功能
http://blog.lujinkai.cn/运维/Nginx/4.Nginx Rewrite 相关功能/
作者
像方便面一样的男子
发布于
2020年12月29日
更新于
2023年12月5日
许可协议