本文已参与「新人创作礼」活动,一起开启掘金创作之路。
location语法详解
语法规则:
location 前缀字符串 URL { [ 配置 ]}
前缀字符串包含:
@ : 内部重定向= :精确匹配,优先级最高。如果找到了这个精确匹配,则停止查找。^~ :URI 以某个常规字符串开头,匹配到最长的前缀字符串,则不检查正则表达式。^ 表示 “非”,~ 表示 “正则”,意思是:不要继续匹配正则~ :区分大小写的正则匹配~* :不区分大小写的正则匹配/ :通用匹配, 优先级最低。任何请求都会匹配到这个规则!~ 和!~* :分别为区分大小写不匹配及不区分大小写不匹配 的正则
优先级为:首先精确匹配 = - 》 其次以xx开头匹配^~ - 》然后是按文件中顺序的正则匹配 ~ ~* -》最后是交给 通用匹配 (不带前缀的 或 /)。
其中 “~ ” 前缀表示匹配区分大小写的正则 location,“* ” 前缀表示匹配不区分大小写的正则 location;其他前缀(包括:“=”,“^ ”和“@ ”)和 无任何前缀的都属于普通 location,= 精确匹配,^~ 不使用正则,@ 内部重定向。
当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
例子,有如下匹配规则:
location = / { #规则A}location = /login { #规则B}location ^~ /static/ { #规则C}location ~ \.(gif|jpg|png|js|css)$ { #规则D,注意:是根据括号内的大小写进行匹配。括号内全是小写,只匹配小写}location ~* \.png$ { #规则E}location !~ \.xhtml$ { #规则F}location !~* \.xhtml$ { #规则G}location / { #规则H}
那么产生的效果如下:
访问根目录/, 比如http://localhost/ 将匹配规则A
访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
访问 http://localhost/static/a.html 将匹配规则C
访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用, 而 http://localhost/static/c.png 则优先匹配到 规则C
访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。
访问 http://localhost/a.xhtml 不会匹配规则F和规则G,
http://localhost/a.XHTML不会匹配规则G,(因为!)。规则F,规则G属于排除法,符合匹配规则也不会匹配到,所以想想看实际应用中哪里会用到。
访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:
#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。#这里是直接转发给后端应用服务器了,也可以是一个静态首页# 第一个必选规则location = / { proxy_pass http://tomcat:8080/index} # 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用location ^~ /static/ { //以xx开头 root /webroot/static/;}location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { //以xx结尾 root /webroot/res/;} #第三个规则就是通用规则,用来转发动态请求到后端应用服务器#非静态文件请求就默认是动态请求,自己根据实际把握location / { proxy_pass http://tomcat:8080/}
ReWrite语法
last
– 基本上都用这个Flag。
break
– 中止Rewirte,不在继续匹配
redirect
– 返回临时重定向的HTTP状态302
permanent
– 返回永久重定向的HTTP状态301
1、下面是可以用来判断的表达式:
-f
和!-f
用来判断是否存在文件
-d
和!-d
用来判断是否存在目录
-e
和!-e
用来判断是否存在文件或目录
-x
和!-x
用来判断文件是否可执行
2、下面是可以用作判断的全局变量
例:http://localhost:88/test1/test2/test.php
$host:localhost$server_port:88$request_uri:http://localhost:88/test1/test2/test.php$document_uri:/test1/test2/test.php$document_root:D:\nginx/html$request_filename:D:\nginx/html/test1/test2/test.php
附:一些可用的全局变量
$args$content_length$content_type$document_root$document_uri$host$http_user_agent$http_cookie$limit_rate$request_body_file$request_method$remote_addr$remote_port$remote_user$request_filename$request_uri$query
if 和 break 指令
if 的可用上下文有:server、location。if 的条件可能是以下任何一种情况:
变量名;如果变量值是空字符串或“0”则为 FALSE。注意,在 1.0.1 版本之前,任何以“0”开头的字符串都会被当做 FALSE。
使用“=”和“!=”的变量跟字符串的比较
使用“”(区分大小写匹配)和“*”(不区分大小写匹配)运算符将变量与正则表达式匹配。正则表达式可以包含捕获,之后可以通过 9 这几个变量名重复使用。“!”和“!*”用作不匹配运算符。如果正则表达式包含“}”或“;”字符,则整个表达式应该用单引号或双引号括起来。
用“-f”和“!-f”运算符检查文件是否存在
用“-d”和“!-d”运算符检查目录是否存在
用“-e”和“!-e”运算符检查文件、目录或符号链接的存在性
用“-x”和“!-x”运算符检查可执行文件
# 如果用户代理 User-Agent 包含"MSIE",rewrite 请求到 /msie/ 目录下。通过正则匹配的捕获可以用 $1 $2 等使用if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break;}# 如果 cookie 匹配正则,设置变量 $id 等于匹配到的正则部分if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1;}# 如果请求方法为 POST,则返回状态 405(Method not allowed)if ($request_method = POST) { return 405;}#比如我们实现login请求返回 200,但是其他请求都302,可以用如下配置location ~ /login { return 200 "test"; break;}if ($request_uri !~ /login) { return 302 https://www.phpmianshi.com$request_uri;}# 如果通过 set 指令设置了 $slow,限速if ($slow) { limit_rate 10k;}# 如果请求的文件存在,则开启缓存,并通过 break 停止后面的检查if (-f $request_filename) { expires max; break;}# 如果请求的文件、目录或符号链接都不存在,则用 rewrite 在 URI 头部添加 /index.phpif (!-e $request_filename) { rewrite ^/(.*)$ /index.php/$1 break;}
break 的可用上下文有:server、location、if。用于停止处理当前的 ngx_http_rewrite_module 指令集合。
return、rewrite 和 try_files 指令
NGINX rewrite 的两个通用指令是 return 和 rewrite,而 try_files 指令可以将请求定向到应用程序服务器。
return 指令简单高效,建议尽量使用 return,而不是 rewrite。
return 指令放在 server 或 location 上下文中。语法很简单:
return code [text];return code URL;return URL;
server { listen 80; listen 443 ssl; server_name www.old-name.com; return 301 $scheme://www.new-name.com$request_uri;}
对于 3xx 系列响应码,url
参数定义了新的(重写过的)URL:
return (301 | 302 | 303 | 307) url;
对于其他响应码,可以选择定义一个出现在响应正文中的文本字符串(HTTP 代码的标准文本,例如 404 的 Not Found,仍包含在标题中)。文本可以包含 NGINX 变量。
return (1xx | 2xx | 4xx | 5xx) ["text"];
例如,在拒绝没有有效身份验证令牌的请求时,此指令可能适用:
return 401 "Access denied because token is expired or invalid";
rewrite 规则会改变部分或整个用户请求中的 URL,主要有两个用途:
通知客户端,请求的资源已经换地方了。例如网站改版后添加了 www 前缀,通过 rewrite 规则可以将所有请求导向新站点。
控制 Nginx 中的处理流程。例如当需要动态生成内容时,将请求转发到应用程序服务器。try_files 指令经常用于这个目的。
但是,如果需要测试 URL 之间更复杂的区别,或者要从原始 URL 中捕获的元素没有对应的 NGINX 变量,或者更改或添加路径中的元素(例如各大 PHP 框架常用的 index.php 入口文件),该怎么办? 可以使用 rewrite 指令。
rewrite 指令放在 server 或 location 上下文中。语法很简单:
rewrite regex URL [flag];
第一个参数 regex 是正则表达式。
flag 支持以下 4 个选项:
last:停止处理当前的 ngx_http_rewrite_module 指令集,并开始对匹配更改后的 URI 的新 location 进行搜索(再从 server 走一遍匹配流程)。此时对于当前 server 或 location 上下文,不再处理 ngx_http_rewrite_module 重写模块的指令。
break:停止处理当前的 ngx_http_rewrite_module 指令集
redirect:返回包含 302 代码的临时重定向,在替换字符串不以“http://”,“https://”或“$scheme”开头时使用
permanent:返回包含 301 代码的永久重定向。
last 和 break 的区别及共同处:
last 重写 url 后,会再从 server 走一遍匹配流程,而 break 终止重写后的匹配
break 和 last 都能阻止后面的 rewrite 指令再次执行
rewrite 指令只能返回代码 301 或 302。要返回其他代码,需要在 rewrite 指令后面包含 return 指令。
rewrite 指令不一定会暂停 NGINX 对请求的处理,因为它不一定会发送重定向到客户端。除非明确指出(使用 flag 或 URL 的语法)你希望 NGINX 停止处理或发送重定向,否则它将在整个配置中运行,查找在重写模块中定义的指令(break、if、return、rewrite 和 set),并按顺序处理。如果重写的 URL 与 Rewrite 模块中的后续指令匹配,NGINX 会对重写的 URL 执行指定的操作(通常会重新写入)。
这是复杂的地方,必须仔细计划指令顺序以获得期望的结果。例如,如果原始 location 块和其中的 NGINX 重写规则与重写的 URL 匹配,NGINX 可以进入一个循环,Nginx 默认限制循序最大 10 次。
下面是使用 rewrite 指令的 NGINX 重写规则的示例。它匹配以字符串 /download 开头的 URL,然后用 /mp3/ 替换在路径稍后的某个位置包含的 /media/ 或 /audio/ 目录,并添加适当的文件扩展名 .mp3 或 .ra。2 变量捕获不变的路径元素。例如,/download/cdn-west/media/file1 变为 /download/cdn-west/mp3/file1.mp3。如果文件名上有扩展名(例如.flv),表达式会将其剥离并用.mp3替换。
server { # ... rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last; rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra last; return 403; # ...}
可以将 flag 添加到重写指令来控制处理流程。示例中的 last 告诉 NGINX 跳过当前服务器或位置块中的任何后续 ngx_http_rewrite_module 重写模块的指令,并开始搜索与重写的 URL 匹配的新位置。
这个例子中的最后一个 return 指令意味着如果 URL 不匹配任何一个 rewrite 指令,将返回给客户端 403 代码。
try_files 指令
try_files 指令也放在 server 或 location 上下文中。语法很简单:
try_files file ... uri;
try_files 指令的参数是一个或多个文件或目录的列表,以及最后面的 URI 参数。
Nginx 会按顺序检查文件及目录是否存在(根据 root 和 alias 指令设置的参数构造完整的文件路径),并用找到的第一个文件提供服务。在元素名后面添加斜杠 / 表示这个是目录。如果文件和目录都不存在,Nginx 会执行内部重定向,跳转到命令的最后一个 uri 参数定义的 URI 中。
要想 try_files 指令工作,必须定义一个 location 块捕捉内部重定向。最后一个参数可以是命名过的 location,由初始符号(@)指示。
try_files 指令通常使用 $uri 变量,表示 URL 中域名之后的部分。
下面示例中,如果客户端请求的文件不存在,Nginx 会响应一个默认的 GIF 文件。假设客户请求“www.domain.com/images/imag… 会首先通过用于这个 location 的 root 和 alias 指令,在本地目录中查找这个文件。如果“image1.gif”文件不存在,Nginx 会查找“image1.gif/”目录,如果都不存在,会重定向到“/images/default.gif”。这个值精确匹配后面的 location 指令,因此处理过程停止,Nginx 返回这个文件,并标注其缓存 30 秒。
location /images/ { try_files $uri $uri/ /images/default.gif;}location = /images/default.gif { expires 30s;}
一些常用的配置
1、Redirect(重定向)语法
server { listen 80; server_name start.igrow.cn; index index.html index.php; root html; if ($http_host !~ "^star\.phpmianshi\.com$" { rewrite ^(.*) http://star.phpmianshi.com$1 redirect; }}
2、防盗链
location ~* \.(gif|jpg|png|bmp)$ { valid_referers none blocked *.ttlsa.com server_names ~\.google\. ~\.baidu\.; if ($invalid_referer) { return 403; #rewrite ^/ http://www.ttlsa.com/403.jpg; }}
3、动静分离
思路:动、静态的文件,请求时匹配不同的目录
当访问gif,jpeg时 直接访问e:wwwroot;
,正则自行配置
server { listen 80; server_name localhost; location / { root /data/wwwroot; index index.html; } # 所有静态请求都由nginx处理,存放目录为html location ~ .(gif|jpg|jpeg|png|bmp|swf|css|js)$ { root /data/static; } # 所有动态请求都转发给tomcat处理 location ~ .(jsp|do)$ { proxy_pass http://test; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /data/wwwroot; } }