“重定向”簡單介紹:
“重定向”指的是HTTP重定向,是HTTP協議的一種機制。當client向server發送一個請求,要求獲取一個資源時,在server接收到這個請求后發現請求的這個資源實際存放在另一個位置,於是server在返回的response中寫入那個請求資源的正確的URL,並設置reponse的狀態碼為301(永久)或者 302(暫時),當client接受到這個response后就會根據新的URL重新發起請求。重定向有一個典型的特症,即,當一個請求被重定向以后,最終瀏覽器上顯示的URL往往不再是開始時請求的那個URL了。這就是重定向的由來。
下面我們先看Redirect的源碼,之后分析完源碼后可以更好的理解其用法。
Tornado Redirect源碼分析:
在 web.py 中發現有倆個地方實現了重定向的機制:
1. 基類 RequestHandler 中定義的 self.redirect:
1 def redirect(self, url, permanent=False, status=None): 2 if self._headers_written: 3 raise Exception("Cannot redirect after headers have been written") 4 if status is None: 5 status = 301 if permanent else 302
6 else: 7 assert isinstance(status, int) and 300 <= status <= 399
8 self.set_status(status) 9 self.set_header("Location", utf8(url)) 10 self.finish()
先看傳入進來的參數:
- url:重定向后所返回的新的URL地址
- permanent:默認為False,表示該重定向為臨時性的;如果為True,則該重定向為永久性。
- status:當status被指定了值的話,那個該值將會作為HTTP返回給客戶端的狀態碼;如果沒有指定特定的值,那么根據上方的permanent狀態,如果permanent為True,則該status返回301;如果permanent為False,則該status返回302。
注: 默認值為302。
分析:
- 通過檢測 self._headers_written 的值,來判斷是否該請求已經被返回給了客戶端: 在 基類 RequestHandler 的初始化中,self._headers_written = False,之后如果當前輸出的緩沖區已經flush到了網絡的時候,函數 def flush() 中會將 self._headers_written = True。所以此時頭信息headers已經別寫入了請求且已經返回給了客戶端,是無法進行重定向了。
- status狀態碼默認為302,除非permanent參數為True(永久重定向)才會返回301。如果status指定了特定的值的話,那么對指定的值進行數據類型判斷,並且status的范圍為 300~399,否則會返回異常。
- 寫入狀態信息,以及 字段“Location” (用來重定向接收方到非請求URL的位置來完成請求或標識新的資源)的值
- 調用 finish() ,完成該HTTP請求。
2. 類 RedirectHandler實現的重定向:
1 class RedirectHandler(RequestHandler): 2 def initialize(self, url, permanent=True): 3 self._url = url 4 self._permanent = permanent 5 6 def get(self, *args): 7 self.redirect(self._url.format(*args), permanent=self._permanent)
介紹和用法:
- 重定向客戶端的GET請求到給定的URL。
- 需要提供關鍵參數URL傳入該處理類中,例如:
1 application = web.Application([ 2 (r"/oldpath", web.RedirectHandler, {"url": "/newpath"}), 3 ])
在Application中調用該 RedirectHandlerf方法,給定參數“url”,其會將 地址’/oldpath‘ 重定向到 ’/newpath‘ 中。
- 該類也支持對重定向URL地址進行正則表達式匹配,例如為了實現交換第一個和第二個參數部分,同事保留其余部分不變:
1 application = web.Application([ 2 (r"/(.*?)/(.*?)/(.*)", web.RedirectHandler, {"url": "/{1}/{0}/{2}"}), 3 ])
最終的URL可以使用格式化方法: str.format,子串會被捕獲然后進行對應的匹配。在上面的例子中,一個 “a/b/c” 的請求能夠被格式化,如下:
str.format("/{1}/{0}/{2}", "a", "b", "c") # -> "/b/a/c"
源碼分析:
- 通過 initiaialize() 函數進行參數 URL, permanent 的初始化。permanent初始化為True,則該重定向為永久化的。
- 定義 get() 函數,調用 基類中定義的 self.redirect 進行重定向的處理。
兩種重定向方法的比較和思考:
對於兩種方法中的 permanent 參數,類 RedirectHandler 中默認為True(永久性重定向301);self.redirect中默認為False(臨時性重定向302);
原因:self.redirect 多數情況下被用於用戶自定義的情況下進行重定向操作(例如環境變更、用戶認證、以及表單提交),所以其默認為臨時的重定向。類RedirectHandler 是每次匹配到該請求URL的時候就觸發重定向。