
<a target="_blank"></a>
一个示例:
<code>location = / {</code>
<code># 精确匹配 / ,主机名后面不能带任何字符串</code>
<code>[ configuration a ]</code>
<code>}</code>
<code>location / {</code>
<code># 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求</code>
<code># 但是正则和最长字符串会优先匹配</code>
<code>[ configuration b ]</code>
<code>location /documents/ {</code>
<code># 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索</code>
<code># 只有后面的正则表达式没有匹配到时,这一条才会采用这一条</code>
<code>[ configuration c ]</code>
<code>location ~ /documents/abc {</code>
<code>[ configuration cc ]</code>
<code>location ^~ /images/ {</code>
<code># 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。</code>
<code>[ configuration d ]</code>
<code>location ~* \.(gif|jpg|jpeg)$ {</code>
<code># 匹配所有以 gif,jpg或jpeg 结尾的请求</code>
<code># 然而,所有请求 /images/ 下的图片会被 config d 处理,因为 ^~ 到达不了这一条正则</code>
<code>[ configuration e ]</code>
<code>location /images/ {</code>
<code># 字符匹配到 /images/,继续往下,会发现 ^~ 存在</code>
<code>[ configuration f ]</code>
<code>location /images/abc {</code>
<code># 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在</code>
<code># f与g的放置顺序是没有关系的</code>
<code>[ configuration g ]</code>
<code>location ~ /images/abc/ {</code>
<code># 只有去掉 config d 才有效:先最长匹配 config g 开头的地址,继续往下搜索,匹配到这一条正则,采用</code>
<code>[ configuration h ]</code>
<code>location ~* /js/.*/\.js</code>
已<code>=</code>开头表示精确匹配
如 a 中只匹配根目录结尾的请求,后面不能带任何字符串。
<code>^~</code> 开头表示uri以某个常规字符串开头,不是正则匹配
~ 开头表示区分大小写的正则匹配;
~* 开头表示不区分大小写的正则匹配
/ 通用匹配, 如果没有其它匹配,任何请求都会匹配到
顺序不等于优先级:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)
上面的匹配结果。按照上面的location写法,以下的匹配示例成立:
/ -> config a
精确完全匹配,即使/index.html也匹配不了
/downloads/download.html -> config b
匹配b以后,往下没有任何匹配,采用b
/images/1.gif -> configuration d
匹配到f,往下匹配到d,停止往下
/images/abc/def -> config d
最长匹配到g,往下匹配d,停止往下
你可以看到 任何以/images/开头的都会匹配到d并停止,fg写在这里是没有任何意义的,h是永远轮不到的,这里只是为了说明匹配顺序
/documents/document.html -> config c
匹配到c,往下没有任何匹配,采用c
/documents/1.jpg -> configuration e
匹配到c,往下正则匹配到e
/documents/abc.jpg -> config cc
最长匹配到c,往下正则顺序匹配到cc,不会往下到e
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:
<code>#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。</code>
<code>#这里是直接转发给后端应用服务器了,也可以是一个静态首页</code>
<code># 第一个必选规则</code>
<code>location = / {</code>
<code>proxy_pass http://tomcat:8080/index</code>
<code># 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项</code>
<code># 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用</code>
<code>location ^~ /static/ {</code>
<code>root /webroot/static/;</code>
<code>location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {</code>
<code>root /webroot/res/;</code>
<code># 第三个规则就是通用规则,用来转发动态请求到后端应用服务器</code>
<code># 非静态文件请求就默认是动态请求,自己根据实际把握</code>
<code># 毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了</code>
<code>location / {</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&u=str</code> 只对<code>/a/we/index.php</code>重写。语法<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指令
语法为<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 ($http_user_agent ~ msie) {</code>
<code>rewrite ^(.*)$ /msie/$1 break;</code>
<code>} //如果ua包含"msie",rewrite请求到/msid/目录下</code>
<code>if ($http_cookie ~* "id=([^;]+)(?:;|$)") {</code>
<code>set $id $1;</code>
<code>} //如果cookie匹配正则,设置变量$id等于正则引用部分</code>
<code>if ($request_method = post) {</code>
<code>return 405;</code>
<code>} //如果提交方法为post,则返回状态405(method not allowed)。return不能返回301,302</code>
<code>if ($slow) {</code>
<code>limit_rate 10k;</code>
<code>} //限速,$slow可以通过 set 指令设置</code>
<code>if (!-f $request_filename){</code>
<code>break;</code>
<code>proxy_pass http://127.0.0.1;</code>
<code>} //如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查</code>
<code>if ($args ~ post=140){</code>
<code>rewrite ^ http://example.com/ permanent;</code>
<code>} //如果query string中包含"post=140",永久重定向到example.com</code>
<code>location ~* \.(gif|jpg|png|swf|flv)$ {</code>
<code>valid_referers none blocked www.jefflei.com www.leizhenfang.com;</code>
<code>if ($invalid_referer) {</code>
<code>return 404;</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>
<code>$host:localhost</code>
<code>$server_port:88</code>
<code>$request_uri:http://localhost:88/test1/test2/test.php</code>
<code>$document_uri:/test1/test2/test.php</code>
<code>$document_root:/var/www/html</code>
<code>$request_filename:/var/www/html/test1/test2/test.php</code>
<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>转义特殊字符。
<code>http {</code>
<code># 定义image日志格式</code>
<code>log_format imagelog '[$time_local] ' $image_file ' ' $image_type ' ' $body_bytes_sent ' ' $status;</code>
<code># 开启重写日志</code>
<code>rewrite_log on;</code>
<code></code>
<code>server {</code>
<code>root /home/www;</code>
<code># 重写规则信息</code>
<code>error_log logs/rewrite.log notice;</code>
<code># 注意这里要用‘’单引号引起来,避免{}</code>
<code>rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;</code>
<code># 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行</code>
<code>set $image_file $3;</code>
<code>set $image_type $4;</code>
<code>location /data {</code>
<code># 指定针对图片的日志格式,来分析图片类型和大小</code>
<code>access_log logs/images.log mian;</code>
<code>root /data/images;</code>
<code># 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里</code>
<code>try_files /$arg_file /image404.html;</code>
<code>location = /image404.html {</code>
<code># 图片不存在返回特定的信息</code>
<code>return 404 "image not found\n";</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状态码。
<code>rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;</code>
对形如<code>/images/bla_500x400.jpg</code>的文件请求,重写到<code>/resizer/bla.jpg?width=500&height=400</code>地址,并会继续尝试匹配location。
<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规则快速上手
<a href="http://fantefei.blog.51cto.com/2229719/919431" target="_blank">http://fantefei.blog.51cto.com/2229719/919431</a>
<b></b>
<b>原文发布时间为:2015-06-30</b>
<b>本文来自云栖社区合作伙伴“linux中国”</b>