天天看点

nginx配置location总结及rewrite规则写法location正则写法Rewrite规则

一个示例:

<code>location  = / {  # 精确匹配 / ,主机名后面不能带任何字符串</code>

<code>  </code><code>[ configuration A ] </code>

<code>}</code>

<code>location  / {  # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求</code>

<code>  </code><code># 但是正则和最长字符串会优先匹配</code>

<code>  </code><code>[ configuration B ] </code>

<code>location /documents/ {  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索</code>

<code>  </code><code># 只有后面的正则表达式没有匹配到时,这一条才会采用这一条</code>

<code>  </code><code>[ configuration C ] </code>

<code>location ~ /documents/Abc {  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索</code>

<code>  </code><code>[ configuration CC ] </code>

<code>location ^~ /images/ {  # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。</code>

<code>  </code><code>[ configuration D ] </code>

<code>location ~* \.(gif|jpg|jpeg)$ {  # 匹配所有以 gif,jpg或jpeg 结尾的请求</code>

<code>  </code><code># 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则</code>

<code>  </code><code>[ configuration E ] </code>

<code>location /images/ {  # 字符匹配到 /images/,继续往下,会发现 ^~ 存在</code>

<code>  </code><code>[ configuration F ] </code>

<code>location /images/abc {  # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在</code>

<code>  </code><code># F与G的放置顺序是没有关系的</code>

<code>  </code><code>[ configuration G ] </code>

<code>location ~ /images/abc/ {  # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用</code>

<code>    </code><code>[ configuration H ] </code>

<code>location ~* /js/.*/\.js</code>

已<code>=</code>开头表示精确匹配

如 A 中只匹配根目录结尾的请求,后面不能带任何字符串。

<code>^~</code> 开头表示uri以某个常规字符串开头,不是正则匹配

~ 开头表示区分大小写的正则匹配;

~* 开头表示不区分大小写的正则匹配

/ 通用匹配, 如果没有其它匹配,任何请求都会匹配到

顺序 no优先级: (location =) &gt; (location 完整路径) &gt; (location ^~ 路径) &gt; (location ~,~* 正则顺序) &gt; (location 部分起始路径) &gt; (/)

上面的匹配结果 按照上面的location写法,以下的匹配示例成立:

/ -&gt; config A

精确完全匹配,即使/index.html也匹配不了

/downloads/download.html -&gt; config B

匹配B以后,往下没有任何匹配,采用B

/images/1.gif -&gt; configuration D

匹配到F,往下匹配到D,停止往下

/images/abc/def -&gt; config D

最长匹配到G,往下匹配D,停止往下

你可以看到 任何以/images/开头的都会匹配到D并停止,FG写在这里是没有任何意义的,H是永远轮不到的,这里只是为了说明匹配顺序

/documents/document.html -&gt; config C

匹配到C,往下没有任何匹配,采用C

/documents/1.jpg -&gt; configuration E

匹配到C,往下正则匹配到E

/documents/Abc.jpg -&gt; config CC

最长匹配到C,往下正则顺序匹配到CC,不会往下到E

<code>所以实际使用中,个人觉得至少有三个匹配规则定义,如下:</code>

<code>#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。</code>

<code>#这里是直接转发给后端应用服务器了,也可以是一个静态首页</code>

<code># 第一个必选规则</code>

<code>location = / {</code>

<code>    </code><code>proxy_pass http://tomcat:8080/index</code>

<code># 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项</code>

<code># 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用</code>

<code>location ^~ /static/ {</code>

<code>    </code><code>root /webroot/static/;</code>

<code>location ~* \.(gif</code><code>|jpg</code><code>|jpeg</code><code>|png</code><code>|css</code><code>|js</code><code>|ico</code><code>)$ {</code>

<code>    </code><code>root /webroot/res/;</code>

<code>#第三个规则就是通用规则,用来转发动态请求到后端应用服务器</code>

<code>#非静态文件请求就默认是动态请求,自己根据实际把握</code>

<code>#毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了</code>

<code>location / {</code>

<code>    </code><code>proxy_pass http://tomcat:8080/</code>

<a href="http://tengine.taobao.org/book/chapter_02.html" target="_blank">http://tengine.taobao.org/book/chapter_02.html</a>

<a href="http://nginx.org/en/docs/http/ngx_http_rewrite_module.html" target="_blank">http://nginx.org/en/docs/http/ngx_http_rewrite_module.html</a>

rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在server{},location{},if{}中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 <code>http://seanlook.com/a/we/index.php?id=1&amp;u=str</code> 只对/a/we/index.php重写。语法<code>rewrite regex replacement [flag];</code>

如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。

表明看rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,它们的执行顺序是:

执行server块的rewrite指令

执行location匹配

执行选定的location中的rewrite指令

如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。

<code>last</code> : 相当于Apache的[L]标记,表示完成rewrite

<code>break</code> : 停止执行当前虚拟主机的后续rewrite指令集

<code>redirect</code> : 返回302临时重定向,地址栏会显示跳转后的地址

<code>permanent</code> : 返回301永久重定向,地址栏会显示跳转后的地址

因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里 last 和 break 区别有点难以理解:

last一般写在server和if中,而break一般使用在location中

last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配

break和last都能组织继续执行后面的rewrite指令

if判断指令

语法为<code>if(condition){...}</code>,对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容:

当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false

直接比较变量和内容时,使用<code>=</code>或<code>!=</code>

<code>~</code>正则表达式匹配,<code>~*</code>不区分大小写的匹配,<code>!~</code>区分大小写的不匹配

<code>-f</code>和<code>!-f</code>用来判断是否存在文件

<code>-d</code>和<code>!-d</code>用来判断是否存在目录

<code>-e</code>和<code>!-e</code>用来判断是否存在文件或目录

<code>-x</code>和<code>!-x</code>用来判断文件是否可执行

例如:

<code>if</code> <code>(</code><code>$http_user_agent</code> <code>~ MSIE) {</code>

<code>    </code><code>rewrite ^(.*)$ /msie/</code><code>$1</code> <code>break</code><code>;</code>

<code>} //如果UA包含</code><code>"MSIE"</code><code>,rewrite请求到/msid/目录下</code>

<code>if</code> <code>(</code><code>$http_cookie</code> <code>~* </code><code>"id=([^;]+)(?:;|$)"</code><code>) {</code>

<code>    </code><code>set </code><code>$id</code> <code>$1</code><code>;</code>

<code> </code><code>} //如果cookie匹配正则,设置变量</code><code>$id</code><code>等于正则引用部分</code>

<code>if</code> <code>(</code><code>$request_method</code> <code>= POST) {</code>

<code>    </code><code>return</code> <code>405;</code>

<code>} //如果提交方法为POST,则返回状态405(Method not allowed)。</code><code>return</code><code>不能返回301,302</code>

<code>if</code> <code>(</code><code>$slow</code><code>) {</code>

<code>    </code><code>limit_rate 10k;</code>

<code>} //限速,</code><code>$slow</code><code>可以通过 set 指令设置</code>

<code>if</code> <code>(!</code><code>-f</code> <code>$request_filename</code><code>){</code>

<code>    </code><code>break</code><code>;</code>

<code>    </code><code>proxy_pass  http://127.0.0.1; </code>

<code>} //如果请求的文件名不存在,则反向代理到localhost 。这里的</code><code>break</code><code>也是停止rewrite检查</code>

<code>if</code> <code>(</code><code>$args</code> <code>~ post=140){</code>

<code>    </code><code>rewrite ^ http://example.com/ permanent;</code>

<code>} //如果query string中包含</code><code>"post=140"</code><code>,永久重定向到example.com</code>

<code>location ~* \.(gif</code><code>|jpg</code><code>|png</code><code>|swf</code><code>|flv</code><code>)$ {</code>

<code>    </code><code>valid_referers none blocked www.jefflei.com www.leizhenfang.com;</code>

<code>    </code><code>if</code> <code>(</code><code>$invalid_referer</code><code>) {</code>

<code>        </code><code>return</code> <code>404;</code>

<code>    </code><code>} //防盗链</code>

全局变量

下面是可以用作if判断的全局变量

<code>$args</code> : #这个变量等于请求行中的参数,同<code>$query_string</code>

<code>$content_length</code> : 请求头中的Content-length字段。

<code>$content_type</code> : 请求头中的Content-Type字段。

<code>$document_root</code> : 当前请求在root指令中指定的值。

<code>$host</code> : 请求主机头字段,否则为服务器名称。

<code>$http_user_agent</code> : 客户端agent信息

<code>$http_cookie</code> : 客户端cookie信息

<code>$limit_rate</code> : 这个变量可以限制连接速率。

<code>$request_method</code> : 客户端请求的动作,通常为GET或POST。

<code>$remote_addr</code> : 客户端的IP地址。

<code>$remote_port</code> : 客户端的端口。

<code>$remote_user</code> : 已经经过Auth Basic Module验证的用户名。

<code>$request_filename</code> : 当前请求的文件路径,由root或alias指令与URI请求生成。

<code>$scheme</code> : HTTP方法(如http,https)。

<code>$server_protocol</code> : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。

<code>$server_addr</code> : 服务器地址,在完成一次系统调用后可以确定这个值。

<code>$server_name</code> : 服务器名称。

<code>$server_port</code> : 请求到达服务器的端口号。

<code>$request_uri</code> : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。

<code>$uri</code> : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。

<code>$document_uri</code> : 与$uri相同。

例:<code>http://localhost:88/test1/test2/test.php</code>

$host:localhost

$server_port:88

$document_uri:/test1/test2/test.php

$document_root:/var/www/html

$request_filename:/var/www/html/test1/test2/test.php

<code>.</code> : 匹配除换行符以外的任意字符

<code>?</code> : 重复0次或1次

<code>+</code> : 重复1次或更多次

<code>*</code> : 重复0次或更多次

<code>\d</code> :匹配数字

<code>^</code> : 匹配字符串的开始

<code>$</code> : 匹配字符串的介绍

<code>{n}</code> : 重复n次

<code>{n,}</code> : 重复n次或更多次

<code>[c]</code> : 匹配单个字符c

<code>[a-z]</code> : 匹配a-z小写字母的任意一个

小括号<code>()</code>之间匹配的内容,可以在后面通过<code>$1</code>来引用,<code>$2</code>表示的是前面第二个<code>()</code>里的内容。正则里面容易让人困惑的是<code>\</code>转义特殊字符。

例1:

<code>http {</code>

<code>    </code><code># 定义image日志格式</code>

<code>    </code><code>log_format imagelog </code><code>'[$time_local] '</code> <code>$image_file</code> <code>' '</code> <code>$image_type</code> <code>' '</code> <code>$body_bytes_sent</code> <code>' '</code> <code>$status</code><code>;</code>

<code>    </code><code># 开启重写日志</code>

<code>    </code><code>rewrite_log on;</code>

<code>    </code><code>server {</code>

<code>        </code><code>root /home/www;</code>

<code>        </code><code>location / {</code>

<code>                </code><code># 重写规则信息</code>

<code>                </code><code>error_log logs/rewrite.log notice; </code>

<code>                </code><code># 注意这里要用‘’单引号引起来,避免{}</code>

<code>                </code><code>rewrite </code><code>'^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$'</code> <code>/data</code><code>?</code><code>file=</code><code>$3</code><code>.</code><code>$4</code><code>;</code>

<code>                </code><code># 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行</code>

<code>                </code><code>set </code><code>$image_file</code> <code>$3</code><code>;</code>

<code>                </code><code>set </code><code>$image_type</code> <code>$4</code><code>;</code>

<code>        </code><code>}</code>

<code>        </code><code>location /data {</code>

<code>                </code><code># 指定针对图片的日志格式,来分析图片类型和大小</code>

<code>                </code><code>access_log logs/images.log mian;</code>

<code>                </code><code>root /data/images;</code>

<code>                </code><code># 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里</code>

<code>                </code><code>try_files /</code><code>$arg_file</code> <code>/image404.html;</code>

<code>        </code><code>location = /image404.html {</code>

<code>                </code><code># 图片不存在返回特定的信息</code>

<code>                </code><code>return</code> <code>404 </code><code>"image not found\n"</code><code>;</code>

对形如<code>/images/ef/uh7b3/test.png</code>的请求,重写到<code>/data?file=test.png</code>,于是匹配到<code>location /data</code>,先看<code>/data/images/test.png</code>文件存不存在,如果存在则正常响应,如果不存在则重写tryfiles到新的image404 location,直接返回404状态码。

例2:

<code>rewrite ^/images/(.*)_(\d+)x(\d+)\.(png</code><code>|jpg</code><code>|gif</code><code>)$ /resizer/</code><code>$1</code><code>.</code><code>$4</code><code>?</code><code>width=</code><code>$2</code><code>&amp;height=</code><code>$3</code><code>? last;</code>

对形如<code>/images/bla_500x400.jpg</code>的文件请求,重写到<code>/resizer/bla.jpg?width=500&amp;height=400</code>地址,并会继续尝试匹配location。

例3:

参考

<a href="http://www.nginx.cn/216.html" target="_blank">http://www.nginx.cn/216.html</a>

<a href="http://www.ttlsa.com/nginx/nginx-rewriting-rules-guide/" target="_blank">http://www.ttlsa.com/nginx/nginx-rewriting-rules-guide/</a>

《老僧系列nginx之rewrite规则快速上手.pdf》

<a href="http://fantefei.blog.51cto.com/2229719/919431" target="_blank">http://fantefei.blog.51cto.com/2229719/919431</a>

本文转自奔跑在路上博客51CTO博客,原文链接http://blog.51cto.com/qiangsh/1866790如需转载请自行联系原作者

qianghong000