概述
核心是一个基类 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转换)又灵活(通过基类和不同状态码的子类)的重定向响应体系。