Nginx内置变量及正则语法

时间:2022-03-08 05:35:52

对于很多Nginx初学者来说,配置文件是必须要看懂的。但是当公司的Nginx配置文件放在你面前的时候你总会被一些带着"$"符号和一大推看不懂的的正则给正懵逼。没错带着"$"好的大家肯定是能首先想到这是一个变量,然后就疯狂的在配置文件里面找关键字,结果一圈照下来啥也没有,这时候大部分人应该就会凭着感觉得判断这个变量到底是什么意思了。其实这也是OK的。但是剩下看不懂正则又应该办呢。这里我就给大家整理了Nginx配置文件中常见的一些变量和正则表达式。

一、Nginx的内置变量

$arg_PARAMETER        客户端GET请求中PARAMETER 字段的值

$args                             客户端请求中的参数

$binary_remote_addr    远程地址的二进制表示

$body_bytes_sent         已发送的消息体字节数

$content_length            HTTP请求信息中content-length的字段

$content_type               请求信息中content-type字段

$cookie_COOKIE          客户端请求中COOKIE头域的值

$document_root           针对当前请求的根路径设置值

$document_uri        与$uri相同

$host                            请求信息中的host头域,如果请求中没有Host行,则等于设置的服务器名

$http_HEADER             HTTP请求信息里的HEADER地段

$http_host                    与$host相同,但是如果请求信息中没有host行,则可能不同客户端cookie信息

$http_cookie                 客户端cookie信息

$http_referer                客户端是从哪一个地址跳转过来的

$http_user_agent        客户端代理信息,也就是你客户端浏览器

$http_via                     最后一个访问服务器的IP

$http_x_forwarded_for         相当于访问网路访问的路径

$is_args                      如果有args的值,则等于"?",否则为空

$limit_rate                   对连接速率的限制

$nginx_version           当前Nginx的版本

$pid                            当前Nginx服务器的进程的进程ID

$query_string             与$args相同

$remote_addr            客户端IP地址

$remote_port             客户端的端口

$remote_user            客户端的用户名,用于 auth basic module验证

$request                     客户端请求

$request_body           客户端发送的报文体

$request_body_file    发送后端服务器的本地临时缓存文件的名称

$request_filename    当前请求的文件路径名,由root或alias指令与URI请求生成

$request_method     请求后端数据的方法,例如"GET","POST"

$request_uri             请求的URI,带参数,不包含主机名

$scheme                   所用的协议,如http或者HTTPS,比如rewrite^(.+)$$scheme://mysite.name$redirect

$sent_http_cache_control        对应http请求头中的Cache-Control,需要打开chrome浏览器,右键检查,选中network,点中其中一个请求的资源

$sent_http_connection             对应http请求中的Connection

$sent_http_content_type          对应http请求中的Content-Type

$sent_last_modified                 对应请求中的Last-Modified

$server_addr                           服务端的地址

$server_port                            请求到达服务器端口号

$server_protocol                      请求协议的版本号,HTTP1.0/HTTP1.1

$uri                                           请求的不带请求参数的URI,可能和最初的值有不同,比如经过重定向之类的

如果上面的变量还没有找到你想要的结果可以点击右边的这个Nginx官方链接地址--->http://nginx.org/en/docs/varindex.html

二、正则表达式

*                             零次或者多次匹配前面的字符表达式,等效于{0,}.;   zo*与“z”和“zoo”匹配

+                             一次或者多次匹配前面的字符表达式,等效于{1,};zo+与“zoo”匹配但是与“z”不匹配

?                            零次或一次匹配前面的字符或子表达式。当该字段紧随任何其他限定符(*、+、?、{n}、{n,}或{n,m})之后时,匹配模式是非常贪婪的,非贪婪模式匹配搜索到的、尽可能少的字符串,而默认的贪婪模式匹配搜索到的、尽可能多的字符串。zo? 与“z”和“zoo”不匹配;o+?只于“oooooo”中的单个o匹配。而o+与所有的“o”匹配。do(es)?与do或者does中的do匹配

^                            匹配搜索字符串以什么开始。如果将^用作括号表达式中的第一个字符,则会对字符集求反,^\d{3}与搜索字符串开始出的3个数字匹配。[^abc]与除abc以为的任何字符匹配

$                            匹配搜索字符串以什么结尾,\d{3}$匹配任何3个数字结尾的

.                             额这里其实是一个点号;匹配除了换行符\n之外的任何单个字符

[]                           标记括号表达式的开始和结尾,[1-4]与1,2,3,4匹配。[^aAeE],除了a,A,e,E之外的匹配

{}                          标记限定符表达式的开始结尾,a{2,3}匹配“aa”和“aaa”

()                           标记子表达式的开始和结尾,Nginx服务器使用该元字符保存自表达式以备将来之用A(\d)与“A0”到“A9”匹配,并保存成一个参数

|                            这个就可以理解成为一个或匹配了;z|food|cunt  匹配z,food ,cunt

/                            此标识符一般在location中 如果一个/就表示默认匹配这个虚拟主机中的所有资源

\b                         与一个字边界匹配,即字与空格间的位置 er\b "never" 中的“er”匹配,但与'verb"中的“er”不匹配

\B                        非边界字符匹配,与\b相反

\D                        匹配非数字

\w                        匹配任意字符

\W                       排除A-Z a-z 0-9和下划线以外的任意字符匹配

[a-z]                    匹配小写字符

[^a-z]                   反字符范围,与上面相反

{n}                        正好匹配n次,n是非负整数;o{2}不匹配boy,但是匹配food

{n,}                       至少匹配n次

{n,m}                    匹配至少n次,最多m次

^和$                      指定搜索字符串的开始和结束为止,这将在搜索字符串包含匹配字符串之外的任何字符时阻止匹配

一些特别的模式修饰符:

  (?i)   即匹配时不区分大小写。表示匹配时不区分大小写。
  (?s)  即Singleline(单行模式)。表示更改.的含义,使它与每一个字符匹配(包括换行 符\n)。
  (?m) 即Multiline(多行模式) 。 表示更改^和$的 含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的 精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
  (?x)  表示如果加上该修饰符,表达式中的空白字符将会被忽略,除非它已经被转义。
  (?e)  表示本修饰符仅仅对于replacement有用,代表在replacement中作为PHP代码。
  (?A)  表示如果使用这个修饰符,那么表达式必须是匹配的字符串中的开头部分。比如说"/a/A"匹配"abcd"。
  (?E)  与"m"相反,表示如果使用这个修饰符,那么"$"将匹配绝对字符串的结尾,而不是换行符前面,默认就打开了这个模式。
  (?U)  表示和问号的作用差不多,用于设置"贪婪模式"。

三,使用正则表达式的几个例子:

Nginx作为一款主流的web服务器,功能强大,在处理请求的方式上也是非常给力的。一般变量和正则出现较多的地方是location区域中,或者是定义日志输出的format格式中。

例子一:Wap端访问PC端域名自动跳转

这个案例的需求是这样子的,假如我使用手机端访问www.baidu.com这条域名,则帮我自动重写为m.baidu.com。而我访问www.souhu.com这条域名,则帮我重写为m.souhu.com这条域名。

if ( $server_name ~ ((|www.|)([if ( $ser|
 #过滤主域名
 if ( $server_name ~ ((www.|)([\S\s]*)) ) {
  set $domain $3;
 }

 #设定初始值
 set $temp 0;

 #判断是否为支付域名
 if ( $host ~* (pay|zf) ) {
  set $temp "${temp}1";
 }

 #判断是否是手机端
 if ($http_user_agent ~* (mobile|nokia|iphone|ipad|android|samsung|htc|blackberry)) {
  set $temp "${temp}2";
 }

 #判断是否跳转
 if ( $temp = "02" ) {
  rewrite ^(.*) https://app.$domain permanent;
 }

分析过程:

首先,我们是需要取得主域名部分,那就少不了使用正则去匹配,假如说以www.baidu.com这条域名为例,我们看到的第一个就是www.这个字段,但是还会存在一种情况就是用户可能会直接输入baidu.com这样子去访问,所以我们这里是用(www.|)去进行匹配,再然后匹配点这个字段,而下面的$3是表示取第三个括号里的值,最后复值给$a这个变量,接下来就是通过$http_user_agent这个内置变量去进行判断用户是使用什么方式访问,然后在进行重定向操作。

例子二:Nginx的IP白名单

这个案例的需求是这样子的,我们的后台访问只允许特定的IP进行访问,假如说别的IP进行访问的话我们将进行跳转到一个别的报错页面,或者直接跳转回首页

#定义初始值
set $my_ip 0;

#判断是否为指定的白名单
if ( $http_x_forwarded_for ~* "10.0.0.1|172.16.0.1" ){
 set $my_ip 1;
}

#不是白名单的IP进行重定向跳转
if ( $my_ip = 0 ){
 rewrite ^/$ /40x.html;
}

分析过程:

这个其实和上面的判断用户是使用电脑访问还是手机访问是一样的,但唯一的区别在于内置变量不同,在Nginx中的内置变量里面$http_x_forwarded_for便是为客户访问的真实ip地址,所以我们使用这个内置变量进行判断就好了,同时添加多了一个初始值;

例子三:重写Url地址,隐藏提交内容

这个案例的需求是这样子的,我们提交一些表单内容后url地址会显示除部分参数,比如http://baidu.com/index.php?user=admin&pass=123,而我们需要将url重写为http://baidu.com/index

rewrite ^/(\w+)/(\w+)/z(\d+) /$1/$2/$3/$arg_x/$arg_y? permanent;
rewrite ^/(\w+)/(\w+)/(\d+)/(\d+)/(\d+) /$1/$2/$3/$4_$5.png permanent;

分析过程:

首先我们想想想url的演变,http://baidu.com/index.php?user=admin&pass=123 => http://baidu.com/index.php/user/admin/pass/123 => http://baidu.com/index,然后我们根据演变进行一步一步的操作,nginx rewrite正则匹配不会匹配问号后的参数,因此需要使用$arg_{参数名}来保留参数,且匹配规则要以问号结尾;最后匹配一些其他项替换就完成重写了