一個示例:
<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 =) > (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># 第一個必選規則</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&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>&height=</code><code>$3</code><code>? last;</code>
對形如<code>/images/bla_500x400.jpg</code>的檔案請求,重寫到<code>/resizer/bla.jpg?width=500&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