關于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的過程
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
<a href="http://s3.51cto.com/wyfs02/M00/74/EC/wKiom1YuOxzDk9XkAABOt1rn9hs806.jpg" target="_blank"></a>
由此可見,如此配置實作了一個最簡單的内部跳轉。
二、再進一步,看一個兩級的rewrite。将html/wordpress/下的ljk.html移到html/ljk/下,并且在location /wordpress 下配置重寫規則
root /usr/local/nginx/html;
location /wordpress {
if (!-e $request_filename) {
rewrite ^/wordpress/(.+\..+)$ /ljk/$1;
}
}
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 标志
rewrite ^/(.+\..+)$ /wordpress/$1 permanent;
通路http://172.16.25.162/ljk.html
GET /ljk.html HTTP/1.1" 301 傳回301
GET /wordpress/ljk.html HTTP/1.1" 200
注意此處産生了兩個請求
*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
<a href="http://s3.51cto.com/wyfs02/M01/74/EC/wKiom1YuL9Dx0oK1AABgIZXQw0U866.jpg" target="_blank"></a>
四、重寫規則後加上 redirect 标志
rewrite ^/(.+\..+)$ /wordpress/$1 redirect;
access_log: 兩個請求
"GET /ljk.html?sds HTTP/1.1" 302 臨時重定向302
"GET /wordpress/ljk.html HTTP/1.1" 200
*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
<a href="http://s3.51cto.com/wyfs02/M01/74/E9/wKioL1YuMCuRKeZnAABgIZXQw0U417.jpg" target="_blank"></a>
由三四得出結論: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 規則不加标志的情況
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标志
rewrite ^/(.+\..+)$ /wordpress/$1 break;
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标志
rewrite ^/(.+\..+)$ /wordpress/$1 last;
GET /ljk.html HTTP/1.1" 200
*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段下走一遍配置。
并且這兩個标志都不會改變浏覽器位址欄的url,且傳回碼亦為200或404等(即對使用者透明)
八、涉及到域名重定向的實驗
server {
}
若rewrite規則後不加标志或者加redircet标志,都會傳回“GET / HTTP/1.1" 302”臨時重定向
當rewrite規則後加permanent 标志,會傳回“GET / HTTP/1.1" 301”永久重定向
希望這篇文章能對了解nginx的rewrite有一些幫助!
本文轉自kai404 51CTO部落格,原文連結:http://blog.51cto.com/kaifly/1706564,如需轉載請自行聯系原作者