天天看點

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