nginx rewrite模塊探究與實驗

關於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

wKiom1YuOxzDk9XkAABOt1rn9hs806.jpg

由此可見,如此配置實現了一個最簡單的內部跳轉。

二、再進一步,看一個兩級的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依然不變

wKioL1YuLuGii2meAABOt1rn9hs667.jpg

以上兩個實驗對用戶透明,用戶通過返回碼或者地址欄url均不可感知rewrite的存在,可以看做‘內部重定向’;那麼什麼時候會產生‘外部重定向’呢,現在先試試Permanent、redirect兩個標誌

三、重寫規則後加上 permanent 標誌

         location / {

           root   /usr/local/nginx/html;

           index  index.shtml index.php index.html;

           if (!-e $request_filename) {

              rewrite ^/(.+\..+)$ /wordpress/$1 permanent;

           }

         }

訪問http://172.16.25.162/ljk.html

access_log:

GET /ljk.html HTTP/1.1" 301     返回301

GET /wordpress/ljk.html HTTP/1.1" 200

注意此處產生了兩個請求

error_log:

*107 "^/(.+\..+)$" matches "/ljk.html", client: 172.16.25.3, server: localhost, request: "GET /ljk.html

       *107 rewritten redirect: "/wordpress/ljk.html", client: 172.16.25.3, server: localhost, request: "GET /ljk.html

瀏覽器地址欄變成了rewrite後的url

wKiom1YuL9Dx0oK1AABgIZXQw0U866.jpg

四、重寫規則後加上 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

wKioL1YuMCuRKeZnAABgIZXQw0U417.jpg

由三四得出結論: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

發佈了50 篇原創文章 · 獲贊 33 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章