nginx location

關於一些對location認識的誤區

1、location 的匹配順序是“先匹配正則,再匹配普通”。

矯正: location 的匹配順序其實是“先匹配普通,再匹配正則”。我這麼說,大家一定會反駁我,因爲按“先匹配普通,再匹配正則”解釋不了大家平時習慣的按“先匹配正則,再匹配普通”的實踐經驗。這裏我只能暫時解釋下,造成這種誤解的原因是:正則匹配會覆蓋普通匹配(實際的規則,比這複雜,後面會詳細解釋)。

2、 location 的執行邏輯跟 location 的編輯順序無關。

矯正:這句話不全對,“普通 location ”的匹配規則是“最大前綴”,因此“普通 location ”的確與 location 編輯順序無關;但是“正則 location ”的匹配規則是“順序匹配,且只要匹配到第一個就停止後面的匹配”;“普通location ”與“正則 location ”之間的匹配順序是?先匹配普通 location ,再“考慮”匹配正則 location 。注意這裏的“考慮”是“可能”的意思,也就是說匹配完“普通 location ”後,有的時候需要繼續匹配“正則 location ”,有的時候則不需要繼續匹配“正則 location ”。兩種情況下,不需要繼續匹配正則 location :( 1 )當普通 location 前面指定了“ ^~ ”,特別告訴 Nginx 本條普通 location 一旦匹配上,則不需要繼續正則匹配;( 2 )當普通location 恰好嚴格匹配上,不是最大前綴匹配,則不再繼續匹配正則。


總結一句話:  “正則 location 匹配讓步普通 location 的嚴格精確匹配結果;但覆蓋普通 location 的最大前綴匹配結果”


官方文檔解釋

REFER:  http://wiki.nginx.org/NginxHttpCoreModule#location

location

syntax: location [=|~|~*|^~|@] /uri/ { … }

default: no

context: server

This directive allows different configurations depending on the URI.

(譯者注:1 、different configurations depending on the URI 說的就是語法格式:location [=|~|~*|^~|@] /uri/ { … } ,依據不同的前綴“= ”,“^~ ”,“~ ”,“~* ”和不帶任何前綴的(因爲[A] 表示可選,可以不要的),表達不同的含義, 簡單的說盡管location 的/uri/ 配置一樣,但前綴不一樣,表達的是不同的指令含義。2 、查詢字符串不在URI範圍內。例如:/films.htm?fid=123 的URI 是/films.htm 。)

It can be configured using both literal strings and regular expressions. To use regular expressions, you must use a prefix:

“~” for case sensitive matching

“~*” for case insensitive matching

譯文:上文講到location /uri/ 可通過使用不同的前綴,表達不同的含義。對這些不同前綴,分下類,就2 大類:正則location ,英文說法是location using regular expressions 和普通location ,英文說法是location using literal strings 。那麼其中“~ ”和“~* ”前綴表示正則location ,“~ ”區分大小寫,“~* ”不區分大小寫;其他前綴(包括:“=”,“^~ ”和“@ ”)和無任何前綴的都屬於普通location 。


To determine which location directive matches a particular query, the literal strings are checked first.

譯文:對於一個特定的 HTTP 請求( a particular query ), nginx 應該匹配哪個 location 塊的指令呢(注意:我們在 nginx.conf 配置文件裏面一般會定義多個 location 的)?匹配 規則是:先匹配普通location (再匹配正則表達式)。注意:官方文檔這句話就明確說了,先普通location ,而不是有些同學的誤區“先匹配正則location ”。


Literal strings match the beginning portion of the query – the most specific match will be used.

前面說了“普通location ”與“正則location ”之間的匹配規則是:先匹配普通location ,再匹配正則location 。那麼,“普通location ”內部(普通location 與普通location )是如何匹配的呢?簡單的說:最大前綴匹配。原文:1、match the beginning portion of the query (說的是匹配URI 的前綴部分beginning portion ); 2 、the most specific match will be used (因爲location 不是“嚴格匹配”,而是“前綴匹配”,就會產生一個HTTP 請求,可以“前綴匹配”到多個普通location ,例如:location /prefix/mid/ {} 和location /prefix/ {} ,對於HTTP 請求/prefix/mid/t.html ,前綴匹配的話兩個location 都滿足,選哪個?原則是:the most specific match ,於是選的是location /prefix/mid/ {} )。


Afterwards, regular expressions are checked in the order defined in the configuration file. The first regular expression to match the query will stop the search.

這段話說了兩層意思,第一層是:“Afterwards, regular expressions are checked ”, 意思是普通location 先匹配,而且選擇了最大前綴匹配後,不能就停止後面的匹配,最大前綴匹配只是一個臨時的結果,nginx 還需要繼續檢查正則location (但至於最終才能普通location 的最大前綴匹配,還是正則location 的匹配,截止當前的內容還沒講,但後面會講)。第二層是“regular expressions are checked in the order defined in the configuration file. The first regular expression to match the query will stop the search. ”,意思是說“正則location ”與“正則location”內部的匹配規則是:按照正則location 在配置文件中的物理順序(編輯順序)匹配的(這句話就說明location 並不是一定跟順序無關,只是普通location 與順序無關,正則location 還是與順序有關的),並且只要匹配到一條正則location ,就不再考慮後面的(這與“普通location ”與“正則location ”之間的規則不一樣,“普通location ”與“正則location ”之間的規則是:選擇出“普通location ”的最大前綴匹配結果後,還需要繼續搜索正則location )。


If no regular expression matches are found, the result from the literal string search is used.

這句話回答了“普通location ”的最大前綴匹配結果與繼續搜索的“正則location ”匹配結果的決策關係。如果繼續搜索的“正則location ”也有匹配上的,那麼“正則location ”覆蓋 “普通location ”的最大前綴匹配(因爲有這個覆蓋關係,所以造成有些同學以爲正則location 先於普通location 執行的錯誤理解);但是如果“正則location ”沒有能匹配上,那麼就用“普通location ”的最大前綴匹配結果。


For case insensitive operating systems, like Mac OS X or Windows with Cygwin, literal string matching is done in a case insensitive way (0.7.7). However, comparison is limited to single-byte locale’s only.

Regular expression may contain captures (0.7.40), which can then be used in other directives.

It is possible to disable regular expression checks after literal string matching by using “^~” prefix.If the most specific match literal location has this prefix: regular expressions aren’t checked.

通常的規則是,匹配完了“普通location ”指令,還需要繼續匹配“正則location ”,但是你也可以告訴Nginx :匹配到了“普通location ”後,不再需要繼續匹配“正則location ”了,要做到這一點只要在“普通location ”前面加上“^~ ”符號(^ 表示“非”,~ 表示“正則”,字符意思是:不要繼續匹配正則)。


By using the “=” prefix we define the exact match between request URI and location. When matched search stops immediately. E.g., if the request “/” occurs frequently, using “location = /” will speed up processing of this request a bit as search will stop after first comparison.

除了上文的“^~ ”可以阻止繼續搜索正則location 外,你還可以加“= ”。那麼如果“^~ ”和“= ”都能阻止繼續搜索正則location 的話,那它們之間有什麼區別呢?區別很簡單,共同點是它們都能阻止繼續搜索正則location ,不同點是“^~ ”依然遵守“最大前綴”匹配規則,然而“= ”不是“最大前綴”,而是必須是嚴格匹配(exact match )。


這裏順便講下“location / {} ”和“location = / {} ”的區別,“location / {} ”遵守普通location 的最大前綴匹配,由於任何URI 都必然以“/ ”根開頭,所以對於一個URI ,如果有更specific 的匹配,那自然是選這個更specific 的,如果沒有,“/ ”一定能爲這個URI 墊背(至少能匹配到“/ ”),也就是說“location / {} ”有點默認配置的味道,其他更specific的配置能覆蓋overwrite 這個默認配置(這也是爲什麼我們總能看到location / {} 這個配置的一個很重要的原因)。而“location = / {} ”遵守的是“嚴格精確匹配exact match ”,也就是隻能匹配 http://host:port/ 請求,同時會禁止繼續搜索正則location 。因此如果我們只想對“GET / ”請求配置作用指令,那麼我們可以選“location = / {} ”這樣能減少正則location 的搜索,因此效率比“location / {}” 高(注:前提是我們的目的僅僅只想對“GET / ”起作用)。


On exact match with literal location without “=” or “^~” prefixes search is also immediately terminated.

前面我們說了,普通location 匹配完後,還會繼續匹配正則location ;但是nginx 允許你阻止這種行爲,方法很簡單,只需要在普通location 前加“^~ ”或“= ”。但其實還有一種“隱含”的方式來阻止正則location 的搜索,這種隱含的方式就是:當“最大前綴”匹配恰好就是一個“嚴格精確(exact match )”匹配,照樣會停止後面的搜索。原文字面意思是:只要遇到“精確匹配exact match ”,即使普通location 沒有帶“= ”或“^~ ”前綴,也一樣會終止後面的匹配。


先舉例解釋下,後面例題會用實踐告訴大家。假設當前配置是:location /exact/match/test.html { 配置指令塊1},location /prefix/ { 配置指令塊2} 和 location ~ \.html$ { 配置指令塊3} ,如果我們請求 GET /prefix/index.html ,則會被匹配到指令塊3 ,因爲普通location /prefix/ 依據最大匹配原則能匹配當前請求,但是會被後面的正則location 覆蓋;當請求GET /exact/match/test.html ,會匹配到指令塊1 ,因爲這個是普通location 的exact match ,會禁止繼續搜索正則location 。


To summarize, the order in which directives are checked is as follows:

Directives with the “=” prefix that match the query exactly. If found, searching stops.

All remaining directives with conventional strings. If this match used the “^~” prefix, searching stops.

Regular expressions, in the order they are defined in the configuration file.

If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.

這個順序沒必要再過多解釋了。但我想用自己的話概括下上面的意思“正則 location 匹配讓步普通location 的嚴格精確匹配結果;但覆蓋普通 location 的最大前綴匹配結果”。


It is important to know that nginx does the comparison against decoded URIs. For example, if you wish to match “/p_w_picpaths/ /test”, then you must use “/p_w_picpaths/ /test” to determine the location.


在瀏覽器上顯示的URL 一般都會進行URLEncode ,例如“空格”會被編碼爲  ,但是Nginx 的URL 的匹配都是針對URLDecode 之後的。也就是說,如果你要匹配“/p_w_picpaths/ /test ”,你寫location 的時候匹配目標應該是:“/p_w_picpaths/ /test ”。


Example:

location   = / {

 # matches the query / only.

 [ configuration A ]

}


location   / {

  # matches any query, since all queries begin with /, but regular

  # expressions and any longer conventional blocks will be

  # matched first.

 [ configuration B ]

}


location ^~ /p_w_picpaths/ {

 # matches any query beginning with /p_w_picpaths/ and halts searching,

 # so regular expressions will not be checked.

 [ configuration C ]

}


location ~* \.(gif|jpg|jpeg)$ {

 # matches any request ending in gif, jpg, or jpeg. However, all

 # requests to the /p_w_picpaths/ directory will be handled by

 # Configuration C.  

 [ configuration D ]

}

上述這4 個location 的配置,沒什麼好解釋的,唯一需要說明的是location / {[configuration B]} ,原文的註釋嚴格來說是錯誤的,但我相信原文作者是瞭解規則的,只是文字描述上簡化了下,但這個簡化容易給讀者造成“誤解:先檢查正則location ,再檢查普通location ”。原文:“matches any query, since all queries begin with /, butregular expressions and any longer conventional blocks will be matched first. ”大意是說:“location / {} 能夠匹配所有HTTP 請求,因爲任何HTTP 請求都必然是以‘/ ’開始的(這半句沒有錯誤)。但是,正則location 和其他任何比‘/ ’更長的普通location (location / {} 是普通location 裏面最短的,因此其他任何普通location 都會比它更長,當然location = / {} 和 location ^~ / {} 是一樣長的)會優先匹配(matched first )。” 原文作者說“ but regular expressions will be matched first. ”應該只是想說正則 location 會覆蓋這裏的 location / {} ,但依然是普通location / {} 先於正則 location 匹配,接着再正則 location 匹配;但其他更長的普通 location ( any longer conventional blocks )的確會先於 location / {} 匹配。


Example requests:

/ -> configuration A

/documents/document.html -> configuration B

/p_w_picpaths/1.gif -> configuration C

/documents/1.jpg -> configuration D

Note that you could define these 4 configurations in any order and the results would remain the same.

需要提醒下:這裏說“in any order ”和“… remain the same ”是因爲上面只有一個正則location 。文章前面已經說了正則location 的匹配是跟編輯順序有關係的。


While nested locations are allowed by the configuration file parser, their use is discouraged and may produce unexpected results.

實際上 nginx 的配置文件解析程序是允許 location 嵌套定義的( location / { location /uri/ {} } )。但是我們平時卻很少看見這樣的配置,那是因爲 nginx 官方並不建議大家這麼做,因爲這樣會導致很多意想不到的後果。


The prefix “@” specifies a named location. Such locations are not used during normal processing of requests, they are intended only to process internally redirected requests (see error_page ,try_files ).

文章開始說了location 的語法中,可以有“= ”,“^~ ”,“~ ”和“~* ”前綴,或者乾脆沒有任何前綴,還有“@ ”前綴,但是後面的分析我們始終沒有談到“@ ”前綴。文章最後點內容,介紹了“@”的用途:“@ ”是用來定義“Named Location ”的(你可以理解爲獨立於“普通location (location using literal strings )”和“正則location (location using regular expressions )”之外的第三種類型),這種“Named Location ”不是用來處理普通的HTTP 請求的,它是專門用來處理“內部重定向(internally redirected )”請求的。注意:這裏說的“內部重定向(internally redirected )”或許說成“forward ”會好點,以爲內internally redirected 是不需要跟瀏覽器交互的,純粹是服務端的一個轉發行爲。


http://www.cnblogs.com/lidabo/p/4169396.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章