Nginx學(xué)習(xí):HTTP核心模塊(三)LocationLocation 是整個 HTTP 模塊中非常重要的一個子模塊,它是為某個請求URI(路徑)建立配置。這個模塊又是屬于 Server 模塊的子模塊,同時它還可以嵌套在另一個 Location 模塊下面,因此,它的作用范圍是 server 和 location 。其實,說白了,也就是我們可以為指定的一些路徑去做一些額外的配置。
看著就復(fù)雜吧?最主要的就是 [] 中的選項,因為它可以有多種匹配模式。不過我們先講一下不配置 Location 是什么情況。 如果我們不配置 Location ,那么根據(jù)請求中的 URL 的 Path 部分,比如:/,它就會找到 root 指定的目錄下的 index 配置指定的文件,比如 index.html ,如果找不到文件,就返回 404 。 假如我們在瀏覽器客戶端指定了訪問路徑,比如 /aaa/aaa.html ,那么就是找 root 指定的目錄下的 aaa 目錄下的 aaa.html 文件。比如在我這里就是 /usr/local/nginx/html/aaa/ 這個目錄下的 aaa.html 文件。 這就是默認的,最正常的一個 Nginx 中 Server 的訪問形式。 而 Location 的作用,就是能夠讓我們訪問 /aaa/aaa.html 時,可以讓他不直接打開 aaa.html ,或者在打開 aaa.html 的時候再做一些別的操作。比如我們先簡單配一個,就用這個 /aaa/aaa.html 。 默認不配的情況下,我們 root 指定的目錄 /aaa 并不存在,更沒有下面的 aaa.html 文件,所以它會直接返回 404 。現(xiàn)在我們就簡單配置一個。
現(xiàn)在你再重載一下配置文件,然后訪問試試,看看是不是訪問這個路徑,它把首頁打開了。可以說,這玩意就是整個 Nginx 的靈魂,或者說,所有的服務(wù)器應(yīng)用中,類似的操作 URI 及訪問路徑的功能,都是靈魂,是服務(wù)器類型應(yīng)用中最重要的部分之一。 匹配規(guī)則路徑匹配會在 URI 規(guī)范化以后進行。所謂規(guī)范化,就是先將 URI 中形如 “%XX” 的編碼字符進行解碼, 再解析 URI 中的相對路徑 “.” 和 “..” 部分, 另外還可能會壓縮相鄰的兩個或多個斜線成為一個斜線。 可以使用前綴字符串或者正則表達式定義路徑。使用正則表達式需要在路徑開始添加 “~*” 前綴 (不區(qū)分大小寫),或者 “~” 前綴(區(qū)分大小寫)。為了根據(jù)請求 URI 查找路徑,Nginx 先檢查前綴字符串定義的路徑 (前綴路徑),在這些路徑中找到能最精確匹配請求 URI 的路徑。然后 Nginx 按在配置文件中的出現(xiàn)順序檢查正則表達式路徑, 匹配上某個路徑后即停止匹配并使用該路徑的配置,否則使用最大前綴匹配的路徑的配置。 路徑可以嵌套,但有例外,后面將提到。 在不區(qū)分大小寫的操作系統(tǒng)(諸如Mac OS X和Cygwin)上,前綴匹配忽略大小寫 (0.7.7) 。但是,比較僅限于單字節(jié)的編碼區(qū)域(one-byte locale)。 正則表達式中可以包含匹配組 (0.7.40) ,結(jié)果可以被后面的其他指令使用。 如果最大前綴匹配的路徑以 “^~” 開始,那么 Nginx 不再檢查正則表達式。 而且,使用“=”前綴可以定義URI和路徑的精確匹配。如果發(fā)現(xiàn)匹配,則終止路徑查找。比如,如果請求 “/” 出現(xiàn)頻繁,定義“l(fā)ocation = /”可以提高這些請求的處理速度, 因為查找過程在第一次比較以后即結(jié)束。這樣的路徑明顯不可能包含嵌套路徑。 在 0.7.1 到 0.8.41 的所有nginx版本中,如果請求匹配的前綴字符串路徑并沒有 “=” 或 “^~” 前綴, 路徑查找過程仍然會停止,而不進行正則表達式匹配。 沒錯,上面全是官方文檔中的說明。能堅持看完吧?看不完咱們就來一個一個的試。 普通匹配與精確匹配先試試最簡單的,也是我們最常見的,那就是啥都不加的,以及加上一個 = 號進行精確匹配的。
不同的 URI 給了不同的狀態(tài)碼返回,便于我們測試。 直接訪問 http://192.168.56.88 或者 http://192.168.56.88/ ,都會進入 202 ,這里是 = 號在起作用,定位到精確匹配。訪問 http://192.168.56.88/index.html ,或者 http://192.168.56.88/xxx (xxx 表示任意其它字符)都會進入 201 。其實 = 號的意思就是,只要訪問的 URI 和我這里是完全對應(yīng)的,就不進行其它匹配了,直接走當前這個 location 下面的內(nèi)容。 普通匹配遵循的是前綴匹配法,這里會比較復(fù)雜,我們列表看一下。
如果注釋掉 /zyblog/ 的配置,我們再測試訪問 /zyblog、/zyblog/ ,這時你會發(fā)現(xiàn),結(jié)尾帶 / 的,走的是 203 ,而不帶 / 的走的是 204 ?,F(xiàn)在將 = 號對應(yīng)的 /zyblog 修改為 /zyblog/ ,那么上面的測試結(jié)果又會反過來。這里在平常進行配置的時候一定要注意,非常容易繞暈。 總結(jié)一下,普通匹配中,如果結(jié)尾沒有 / ,是類似于正則中 /zyblog* 的意思,如果有 / 則是 /zyblog/* 的意思。而 = 號是完全匹配,和等號后面完全一樣的才可以。 正則匹配正則匹配就是可以使用正則表達式來進行復(fù)雜的 URI 定義的匹配。
上面的兩個例子中,~* 表示忽略大小寫,~ 表示區(qū)分大小寫。我們可以直接這樣來測試,http://192.168.56.88/1.mp4 和 http://192.168.56.88/1.MP4 都是走的 205 ,http://192.168.56.88/1.JPEG 走的是 206 ,但 http://192.168.56.88/1.jpeg 則會走 201 ,因為大小寫沒匹配到 206。 最后那個 $ 符號表示要以指定正則的內(nèi)容結(jié)尾,比如我們現(xiàn)在嘗試 http://192.168.56.88/1.mp4/123123,返回的是201,去掉符號之后,再次請求,返回的就是 205 了。除此之外,還有一個 ^ ,表示要以正則里的內(nèi)容開頭,其實這兩個符號和普通的正則規(guī)則都是一樣的。
像上面這個配置,就只有 a 開頭,以 flv 或 mp5 結(jié)尾的可以匹配到,其它 URI 都不會匹配到這個 location 。注意,~ 和 ^ ,$ 和 { 之間都要有空格的哦。另外這個 207 的返回值我們還加上了一個 $1$2,其實取得就是正則中每一個括號的里面的值。 最后,還有一點,正則是按先后順序匹配的,在上面的兩個正則條件中,都有 gif 這個條件,當我們訪問 http://192.168.56.88/1.gif 時,會走哪個呢?很明顯,它會走第一個 205 ,正則和正則之間的優(yōu)先級按配置文件中的順序確定。 非正則非正則匹配使用的是 ^~ ,啥意思呢?
其實呀,就是只要是訪問 /r 目錄下的內(nèi)容,都會返回 208 ,不會走后面的其它正則匹配了(可以嘗試去掉 ^~ 會發(fā)現(xiàn)會走后面.txt的正則匹配)?,F(xiàn)在你可以訪問 http://192.168.56.88/r/ 、http://192.168.56.88/r、http://192.168.56.88/r/1.jpg ,返回的都是 208 。即使 1.jpg 其實是匹配到了正則中的那個 jpg 相關(guān)的配置,但還是會走 ^~ 的配置。除非,在它底下再使用 普通規(guī)則 或者 精確規(guī)則 。http://192.168.56.88/r/3.txt 會返回 209 ,http://192.168.56.88/r/2.txt 會返回 210 。 匹配優(yōu)先級從上面的學(xué)習(xí)中,我們其實可以看出,幾種不同的匹配規(guī)則的優(yōu)先級順序。
除了優(yōu)先級之外,還有個匹配順序的問題,比如說面試的時候給出上面的一堆配置,然后問這些問題:
暈頭轉(zhuǎn)向吧?那就對了,這東西就是容易讓人暈頭轉(zhuǎn)向,重點還是把握住上面的優(yōu)先級規(guī)則,另外,在現(xiàn)實的生產(chǎn)環(huán)境中,盡量別配太復(fù)雜的正則,懂得都懂。在進行配置的時候,本地或者測試機多測試一下才是王道。 嵌套location 是可以嵌套在另一個 location 中的。
有點亂吧,不過應(yīng)該也比較清晰,/zy/xxx、/zy/bar/xxx 會返回 213 和 212 ,而 /zy/bar/baz 及這個 URI 下面的所有內(nèi)容會返回 211 ,/zy/bar 會返回 212 。它們?nèi)齻€層級組成了三層嵌套的關(guān)系。 @符號這個 @ 符號,表示一個命名路徑,有這個符號的 location 不參與路徑解析。
比如上面的配置,我們直接訪問 /cc 是沒有效果的,而訪問 /test/at 才會返回 214 的內(nèi)容,也就是說,@ 符號定義的 location 是需要配合 try_files 這類的指令進行操作的??梢援斪鰞?nèi)部使用的一些預(yù)備命名路徑。 結(jié)尾 / 問題
root根目錄為請求設(shè)置根目錄。
默認就是當前運行環(huán)境下的 html 目錄,比如我的 Nginx 的安裝目錄是 /usr/local/nginx ,默認情況下就是這個目錄的相對路徑 ,它的默認值就是 /usr/local/nginx/html ,也可以配置成絕對路徑。大家在正式開發(fā)以及線上環(huán)境使用時,通常都會設(shè)置一個項目的基礎(chǔ)路徑,往往就需要通過 root 來指定。而且這個配置指令其實更多的會配置到 Server 下面,只不過我們將它放到了 Location 一起講解,另外它在 http 下也可以進行全局的配置。順序是 location 沒配就找 server 的,server 也沒配就找 http 的,http 也沒配呢?就是上面說的默認值嘛。要是這個文件夾還沒有呢?404 或者 403 或者什么錯誤唄,反正我沒試過,大家自己試試吧。
訪問 /i/top.gif 的話,將使用的是 /data/w/i/top.gif 文件。文件路徑的構(gòu)造僅僅是將 URI 拼在 root 指令的值后面。
對于這兩個配置,我們設(shè)置的目錄都是 /home/www/html1 這個目錄,但稍有不同,/root_test2 的配置中,root 的最后多了一個斜杠。然后在實際的目錄中,/home/www/html1/root_test1 目錄下有一個 index.html 文件,/home/www/html1/root_test2 目錄下有一個 1.html 文件。以下是訪問的情況說明,順帶演示結(jié)尾 / 的問題:
將 location 中的末尾斜杠去掉。
root 目錄末尾的斜杠和上面測試的報錯沒有關(guān)系,將 root_test1 中的 index.html 改名或者刪除,使用 /root_test1/ 訪問,一樣會報 403 錯誤。也就是說,目錄末尾那個斜杠基本沒啥影響,上面兩種寫法基本是一樣的。但是在沒有默認 index 的情況下,訪問路徑帶不帶末尾的斜杠則會產(chǎn)生不同的效果,不帶的會正常返回 404 ,而帶的則會報 403 錯誤。這一點大家在配置的時候是需要注意的。403 錯誤的問題我們在文章最后會說到。 配置中 path 參數(shù)的值中可以包含除 $document_root 和
那么訪問 /i/1.gif ,訪問的目錄路徑就是 /home/www/html1/1.gif 。一定要區(qū)分清楚 root 和 alias 的區(qū)別。 alias別名替換路徑這個別名替換的意思其實是替換的 root 這個配置指令。先看下這它的配置指令。
它主要用于定義指定路徑的替換路徑。啥意思?如果我們在當前這個 location 中,沒有指定 root ,那么 root 會向上尋找,比如我們在 server 定義的 root 。
如果我們不使用 alias ,那么 /i 將會訪問 /usr/local/nginx/html/i 這個目錄,但是現(xiàn)在,它將替換成 /home/www/html1這個目錄。在 /home/www/html1 目錄下新建一個 index.html ,里面就直接寫一行字,然后訪問一下 http://192.168.56.88/i 看看是不是你寫的那行字。 注意 alias 結(jié)尾的斜杠,alias 是將請求中除 /i 路徑之外的路徑直接拼接到后面。因此,如果沒有結(jié)尾的斜杠的話,訪問 /i/1.gif ,將會查找的是 /home/www/html11.gif 這樣一個路徑。同理,如果我們只是訪問路徑,也需要注意最后的斜杠問題。這一點大家可以自己試一下哦,location 上的斜杠和 alias 的斜杠也會有相互影響。 對于圖片、視頻或者子目錄來說,都是一樣的效果。另外,它還可以針對正則進行操作實現(xiàn)類似于文件名重寫的功能。
看出來是什么意思了嘛,Location 的正則規(guī)則是 /i/xxxx.htm 都可以匹配。然后,我們需要拿到 xxxx 的內(nèi)容,這里就使用了一個括號。一般的正則表達式,括號都可以通過類似于 $0-N 這樣的方式拿到,一般 $0 是整個正則的匹配內(nèi)容,而 $1 就是第一個括號里面的匹配內(nèi)容。因此,我們在現(xiàn)在就通過 $1 獲取到括號中的內(nèi)容。 接下來我在 /home/www/html1 目錄下建立兩個文件,分別是 new_a.html 和 new_b.html 文件。內(nèi)容隨便自己寫,能區(qū)分開就好了。 最后訪問 http://192.168.56.88/i/a.htm 或 http://192.168.56.88/i/b.htm ,結(jié)果會顯示 new_a.html 和 new_b.html 的內(nèi)容。 是不是很好玩?。∵@里需要注意的是,如果配置成目錄并且訪問目錄的話,那么只會找別名目錄下的 index.html 文件。 最后,如果路徑需要對應(yīng)指令 path 值的最后一部分,比如說
那么其實不如直接就使用 root 還好些。
一定要注意它和root之間的區(qū)別,一開始我也是懵圈的,而且很容易搞混。 內(nèi)部訪問 Location內(nèi)部訪問的意思就是只能通過 Nginx 內(nèi)部訪問,無法從外部直接訪問的 URI 。它的配置非常簡單,在 location 中添加一個配置指令即可。
就這么簡單的一個指令,可以指定一個路徑是否只能用于內(nèi)部訪問。如果是外部訪問,客戶端將收到 404 (Not Found) 錯誤。下面的這些請求被看作是內(nèi)部請求:
明白啥意思了沒?其實就是我們直接使用瀏覽器訪問的話,這個有 internal 配置的 location 就會返回 404 。來試下吧。
上面的配置是默認情況下 nginx.conf 中對于 500 系列相關(guān)錯誤的處理,直接跳轉(zhuǎn)到 Nginx 運行目錄下的 html 文件夾中的 50x.html ?,F(xiàn)在直接訪問 http://192.168.56.88/50x.html ,是可以直接看到那個 50x.html 靜態(tài)頁面的。而如果加上 internal ,就像下面這樣。
現(xiàn)在直接訪問 http://192.168.56.88/50x.html ,會返回 404 ,我們再添加一個 location 。
這個 location 的意思是訪問 /to500 這個 URI 后,直接通過重寫指令轉(zhuǎn)換給另一個 location 處理。然后進行測試,會發(fā)現(xiàn)我們可以正??吹?50x.html 頁面的內(nèi)容了。 循環(huán)重定向Nginx 限制每個請求只能最多進行 10 次內(nèi)部重定向,以防配置錯誤引起請求處理出現(xiàn)問題。如果內(nèi)部重定向次數(shù)已達到 10 次,Nginx 將返回 500 (Internal Server Error) 錯誤。同時,錯誤日志中將有 “rewrite or internal redirection cycle” 的信息。這一點也比較好測,不停地向自己跳轉(zhuǎn)就好了。
還是使用 /to500 這個路徑,然后訪問一下,就會發(fā)現(xiàn)出現(xiàn)了 500 錯誤。接著我們看下 error.log 里面的內(nèi)容。
很明確的報錯信息吧,以后如果看到 “rewrite or internal redirection cycle” 的報錯信息了,趕緊檢查一下是不是有循環(huán)重定向的問題吧。 無目錄或者無index.html如果我們 location 指定的目錄在 root 路徑下不存在會是什么情況?
不管怎么訪問,都會是 404 的錯誤頁面。那么如果只有一個目錄,里面是空的呢?也就是說,沒有默認的 index.html 文件存在。
直接訪問 /noindex/ ,返回的是 403 ,直接訪問 /noindex ,會 301 ,訪問 /noindex/xxx.html 返回的是 404 。Nginx 將目錄訪問會定位到 index 指定的文件,默認就是 index.html ,如果找不到這個文件,就統(tǒng)一報 403 。注意,它和權(quán)限沒關(guān)系,即使你把 noindex 的目錄權(quán)限改為 www 也是沒用的,還是報 403 錯誤。 總結(jié)好了,HTTP 模塊中,最最核心的兩個部分:Server 和 Location 子模塊都學(xué)習(xí)完了,剩下的,就是一大堆大大小小的配置項,根據(jù)功能的不同,也進行了一些拆分組合,盡量將相同類似的功能配置放在了一起。后續(xù)的內(nèi)容還非常多,咱們只是剛剛起了個小步而已,大家要跟上哦。 參考文檔: http:///en/docs/http/ngx_http_core_module.html#location |
|
來自: 硬核項目經(jīng)理 > 《待分類》