概述
核心是一個基類 HttpResponseRedirectBase
,以及兩個具體的子類 HttpResponseRedirect
(302 臨時重定向)和 HttpResponsePermanentRedirect
(301 永久重定向)。它們都是 HttpResponse
的子類,專門用于告訴客戶端(通常是瀏覽器)跳轉到另一個URL。
class HttpResponseRedirectBase(HttpResponse):allowed_schemes = ['http', 'https', 'ftp']def __init__(self, redirect_to, *args, **kwargs):super().__init__(*args, **kwargs)self['Location'] = iri_to_uri(redirect_to)parsed = urlparse(str(redirect_to))if parsed.scheme and parsed.scheme not in self.allowed_schemes:raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)url = property(lambda self: self['Location'])def __repr__(self):return '<%(cls)s status_code=%(status_code)d%(content_type)s, url="%(url)s">' % {'cls': self.__class__.__name__,'status_code': self.status_code,'content_type': self._content_type_for_repr,'url': self.url,}class HttpResponseRedirect(HttpResponseRedirectBase):status_code = 302class HttpResponsePermanentRedirect(HttpResponseRedirectBase):status_code = 301
逐行解析
1. 基類:HttpResponseRedirectBase
class HttpResponseRedirectBase(HttpResponse):allowed_schemes = ['http', 'https', 'ftp']
- 繼承:它繼承自
HttpResponse
,這意味著它擁有所有普通HTTP響應的特性(如狀態碼、頭部、內容等),并在此基礎上增加了重定向的特殊功能。 - 類屬性
allowed_schemes
:這是一個非常重要的安全特性。它定義了一個白名單,列出了允許重定向到的URL協議(scheme)。默認只允許'http'
,'https'
,'ftp'
。這可以防止一種稱為不安全的URL重定向的安全漏洞,例如,如果有人試圖構造一個javascript:alert('xss')
或data:text/html;base64,...
這樣的惡意鏈接,由于其協議(javascript:
,data:
)不在白名單內,重定向將會被阻止并拋出異常。
def __init__(self, redirect_to, *args, **kwargs):super().__init__(*args, **kwargs)
- 構造函數:接受一個必需的參數
redirect_to
(要重定向到的目標URL),以及其他任何父類HttpResponse
可能接受的參數(如content
,content_type
等)。 - 調用父類構造函數:
super().__init__(*args, **kwargs)
確保HttpResponse
被正確初始化。
self['Location'] = iri_to_uri(redirect_to)
- 設置Location頭部:這是實現重定向的關鍵。HTTP協議規定,重定向響應必須在
Location
頭部中包含目標URL。這里通過將字典式的賦值(self['Location']
)來設置響應頭。 - iri_to_uri函數:這是一個Django的工具函數,用于將國際化資源標識符(IRI) 轉換為標準的統一資源標識符(URI)。IRI支持Unicode字符(如中文),而URI只允許使用ASCII字符。這個函數會正確處理非ASCII字符的編碼(例如,將“中文”轉換為
%E4%B8%AD%E6%96%87
)。
parsed = urlparse(str(redirect_to))if parsed.scheme and parsed.scheme not in self.allowed_schemes:raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
- 安全驗證:
urlparse(str(redirect_to))
:使用Python的urllib.parse.urlparse
函數解析目標URL,將其拆分成各個組成部分(scheme, netloc, path等)。- 檢查解析出的協議(
parsed.scheme
)是否存在且不在允許的協議白名單(self.allowed_schemes
)中。 - 如果協議不被允許,則拋出一個
DisallowedRedirect
異常,中止重定向過程。這是防止安全漏洞的關鍵防線。
url = property(lambda self: self['Location'])
- 只讀屬性
url
:使用property
裝飾器創建了一個名為url
的只讀屬性。當你訪問response.url
時,它會返回Location
頭部的值,即重定向的目標URL。這提供了一個非常方便和直觀的訪問方式。
def __repr__(self):return '<%(cls)s status_code=%(status_code)d%(content_type)s, url="%(url)s">' % {'cls': self.__class__.__name__,'status_code': self.status_code,'content_type': self._content_type_for_repr,'url': self.url,}
- 對象表示:定義了
__repr__
方法,當你在Python shell中打印這個響應對象時,它會返回一個格式化的、信息豐富的字符串,而不是默認的晦澀的內存地址。例如:<HttpResponseRedirect status_code=302, url="https://example.com/">
。這在調試時非常有用。
2. 具體實現類:HttpResponseRedirect
和 HttpResponsePermanentRedirect
這兩個類非常簡單,它們只做了一件事:繼承基類并設置正確的HTTP狀態碼。
class HttpResponseRedirect(HttpResponseRedirectBase):status_code = 302
- 302 臨時重定向:HTTP狀態碼302表示所請求的資源暫時位于另一個URI下。客戶端(如瀏覽器或搜索引擎爬蟲)在遇到此重定向時,應該繼續使用原始URL發起請求,因為這次重定向可能是臨時的。
class HttpResponsePermanentRedirect(HttpResponseRedirectBase):status_code = 301
- 301 永久重定向:HTTP狀態碼301表示所請求的資源已永久移動到新的URI。客戶端(尤其是搜索引擎爬蟲)在遇到此重定向后,應該更新其書簽或索引,將來所有的請求都應直接發送到新的URL。這對SEO有重要意義。
總結與使用場景
特性 | HttpResponseRedirect (302) | HttpResponsePermanentRedirect (301) |
---|---|---|
狀態碼 | 302 | 301 |
語義 | 臨時移動 | 永久移動 |
瀏覽器行為 | 會繼續使用原URL發起請求 | 可能會緩存重定向,后續直接請求新URL |
SEO影響 | 原URL的權重和排名通常不會傳遞到新URL | 原URL的權重和排名會傳遞到新URL |
常見使用場景 | 用戶登錄后跳轉、表單提交后跳轉(Post/Redirect/Get模式) | 網站改版更換URL結構、HTTP升級到HTTPS |
在實際視圖中的用法
在Django視圖中,你通常不會直接實例化這些類,而是使用更簡短的快捷函數 redirect()
,它內部就是創建這些類的實例。
等效的寫法:
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.shortcuts import redirect# 方法一:直接使用類(顯式,稍顯冗長)
def my_view(request):return HttpResponseRedirect('/some/url/')# 或者 return HttpResponsePermanentRedirect('/some/url/')# 方法二:使用redirect()快捷函數(推薦,更靈活)
def my_view(request):# redirect() 函數默認返回 302 重定向return redirect('/some/url/') # 可以傳遞一個模型對象,它會自動調用 get_absolute_url()# return redirect(some_model_object) # 可以傳遞一個視圖名和參數# return redirect('view-name', arg=arg) # 要返回 301 重定向,使用 permanent 參數return redirect('/some/url/', permanent=True)
總之,這段代碼展示了Django如何通過面向對象的繼承和組合,構建出一個既安全(通過協議白名單和IRI轉換)又靈活(通過基類和不同狀態碼的子類)的重定向響應體系。