關於nginx中的rewrite,之前的理解總感覺有些不精確。比如以下問題,經過rewrite之後:
什麼情況會返回200?
什麼情況會返回301/302?
什麼情況瀏覽器裏的url不變?
什麼情況瀏覽器裏的url會變?
什麼情況匹配一次就不再匹配之後的規則或location?
什麼情況匹配到一條規則後,會以rewrite之後的url再到server段走一遍
如果讀者能理解清楚以上問題,則說明對nginx的rewrite整體上已經有了全面的認識。
接下來我們針對以上問題,來通過試驗逐一解答
實驗環境:nginx 1.8
網站根目錄:nginx/html
注:在http段或者server段添加rewrite_log on;並且設置error_log爲notice級別,可以在error og裏捕捉到rewrite的過程
一、先實驗一個最簡單的:http://172.16.25.162/ljk.html。該文件不在在html下,而在在html/wordpress下
server { listen 80; server_name localhost; rewrite_log on; location / { root /usr/local/nginx/html; index index.shtml index.php index.html; if (!-e $request_filename) { rewrite ^/(.+\..+)$ /wordpress/$1; } } 觀察nginx訪問日誌和錯誤日誌 access_log: "GET /ljk.html HTTP/1.1" 200 error_log: *98 "^/(.+\..+)$" matches "/ljk.html", client: 172.16.25.3, server: localhost, request: "GET /ljk.html *98 rewritten data: "/wordpress/ljk.html", args: "", client:172.16.25.3, server: localhost, request: "GET /ljk.html 瀏覽器裏的url沒有改變,狀態碼返回200 由此可見,如此配置實現了一個最簡單的內部跳轉。 |
二、再進一步,看一個兩級的rewrite。將html/wordpress/下的ljk.html移到html/ljk/下,並且在location /wordpress 下配置重寫規則
location / { root /usr/local/nginx/html; index index.shtml index.php index.html; if (!-e $request_filename) { rewrite ^/(.+\..+)$ /wordpress/$1; } } location /wordpress { if (!-e $request_filename) { rewrite ^/wordpress/(.+\..+)$ /ljk/$1; } } access_log: "GET /ljk.html HTTP/1.1" 200 error_log:可以看到兩次匹配與重寫的過程 *99 "^/(.+\..+)$" matches "/ljk.html", client: 172.16.25.3, server: localhost, request: "GET /ljk.html *99 rewritten data: "/wordpress/ljk.html", args: "", client:172.16.25.3, server: localhost, request: "GET /ljk.html *99 "^/wordpress/(.+\..+)$" matches "/wordpress/ljk.html", client: 172.16.25.3, server: localhost, request: "GET /ljk.html *99 rewritten data: "/ljk/ljk.html", args: "", client: 172.16.25.3, server: localhost, request: "GET /ljk.html 瀏覽器url依然不變 |
以上兩個實驗對用戶透明,用戶通過返回碼或者地址欄url均不可感知rewrite的存在,可以看做‘內部重定向’;那麼什麼時候會產生‘外部重定向’呢,現在先試試Permanent、redirect兩個標誌
三、重寫規則後加上 permanent 標誌
四、重寫規則後加上 redirect 標誌
location / { root /usr/local/nginx/html; index index.shtml index.php index.html; if (!-e $request_filename) { rewrite ^/(.+\..+)$ /wordpress/$1 redirect; } access_log: 兩個請求 "GET /ljk.html?sds HTTP/1.1" 302 臨時重定向302 "GET /wordpress/ljk.html HTTP/1.1" 200 error_log: *108 "^/(.+\..+)$" matches "/ljk.html", client: 172.16.25.3, server: localhost, request: "GET /ljk.html *108 rewritten redirect: "/wordpress/ljk.html?sds", client: 172.16.25.3, server: localhost, request: "GET /ljk.ht ml?sds 瀏覽器地址欄變成了rewrite後的url |
由三四得出結論:Permanent、redirect兩個標誌控制是否將重過程在用戶端體現出來(即將重寫後的url顯示在客戶端)同時返回301 or 302。
然後再試試last和break兩個標誌(需要兩層及以上跳轉來測試)
按照網上較爲普遍的說法:
假如一個location裏有多條rewrite規則,都是不在該location繼續往下匹配,但是
last: 匹配完該條語句後得到的url,重新到server標籤下走一遍
break:到此爲止(直接以重寫後的url在服務器尋找資源)
實驗環境:刪除html/wordpress下的ljk.html,將ljk.html放置在html/ljk/ljk.html,然後在server標籤下配置location /wordpress 的rewrite規則
五、先來看下兩次rewrite 規則不加標誌的情況
location / { root /usr/local/nginx/html; index index.shtml index.php index.html; if (!-e $request_filename) { rewrite ^/(.+\..+)$ /wordpress/$1; } } location /wordpress { if (!-e $request_filename) { rewrite ^/wordpress/(.+\..+)$ /ljk/$1; } } access_log: GET /ljk.html HTTP/1.1" 200 error_log: 經歷兩次匹配和重寫 *111 "^/(.+\..+)$" matches "/ljk.html", *111 rewritten data: "/wordpress/ljk.html", args: "", *111 "^/wordpress/(.+\..+)$" matches "/wordpress/ljk.html", *111 rewritten data: "/ljk/ljk.html", args: "", 瀏覽器地址欄url不變 |
六、實驗break標誌
location / { root /usr/local/nginx/html; index index.shtml index.php index.html; if (!-e $request_filename) { rewrite ^/(.+\..+)$ /wordpress/$1 break; } } location /wordpress { if (!-e $request_filename) { rewrite ^/wordpress/(.+\..+)$ /ljk/$1; } } access_log: GET /ljk.html HTTP/1.1" 404 error_log: *112 "^/(.+\..+)$" matches "/ljk.html", *112 rewritten data: "/wordpress/ljk.html", args: "", *112 open() "/usr/local/nginx/html/wordpress/ljk.html" failed (2: No such file or directory), 加了break,所以在重寫成‘wordpress/ljk.html’就沒有再走到location /wordpress |
七、實驗last標誌
location / { root /usr/local/nginx/html; index index.shtml index.php index.html; if (!-e $request_filename) { rewrite ^/(.+\..+)$ /wordpress/$1 last; } } location /wordpress { if (!-e $request_filename) { rewrite ^/wordpress/(.+\..+)$ /ljk/$1; } } 訪問http://172.16.25.162/ljk.html access_log: GET /ljk.html HTTP/1.1" 200 error_log: *113 "^/(.+\..+)$" matches "/ljk.html", *113 rewritten data: "/wordpress/ljk.html", args: "", *113 "^/wordpress/(.+\..+)$" matches "/wordpress/ljk.html", *113 rewritten data: "/ljk/ljk.html", args: "", |
由五六七可得出結論:
加break標誌時,url一旦找到匹配額規則,就會停止繼續匹配並以該rewrite後額url去服務器請求資源;
加last標誌或者不加任何標誌,其‘過程’和‘結果’一致,會以rewrite後的url再重新到server段下走一遍配置。
(The
last
flag in the example is one of them: it tells NGINX to skip any subsequent Rewrite‑module directives in the current
server
or location
block and start a search for a new
location
that matches the rewritten URL.)
並且這兩個標誌都不會改變瀏覽器地址欄的url,且返回碼亦爲200或404等(即對用戶透明)
八、涉及到域名重定向的實驗
server { listen 80; server_name localhost; rewrite_log on; rewrite ^(.*)$ http://www.baidu.com; } 若rewrite規則後不加標誌或者加redircet標誌,都會返回“GET / HTTP/1.1" 302”臨時重定向 當rewrite規則後加permanent 標誌,會返回“GET / HTTP/1.1" 301”永久重定向 |
希望這篇文章能對理解nginx的rewrite有一些幫助!
本文出自 “奮進的K” 博客,請務必保留此出處http://kaifly.blog.51cto.com/3209616/1706564