深入解析Django重定向机制

概述

核心是一个基类 HttpResponseRedirectBase,以及两个具体的子类 HttpResponseRedirect(302 临时重定向)和 HttpResponsePermanentRedirect(301 永久重定向)。它们都是 HttpResponse 的子类,专门用于告诉客户端(通常是浏览器)跳转到另一个URL。

python 复制代码
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 = 302


class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
    status_code = 301

逐行解析

1. 基类:HttpResponseRedirectBase
python 复制代码
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:)不在白名单内,重定向将会被阻止并抛出异常。
python 复制代码
    def __init__(self, redirect_to, *args, **kwargs):
        super().__init__(*args, **kwargs)
  • 构造函数 :接受一个必需的参数 redirect_to(要重定向到的目标URL),以及其他任何父类 HttpResponse 可能接受的参数(如 content, content_type 等)。
  • 调用父类构造函数super().__init__(*args, **kwargs) 确保 HttpResponse 被正确初始化。
python 复制代码
        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)。
python 复制代码
        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)
  • 安全验证
    1. urlparse(str(redirect_to)):使用Python的 urllib.parse.urlparse 函数解析目标URL,将其拆分成各个组成部分(scheme, netloc, path等)。
    2. 检查解析出的协议(parsed.scheme)是否存在且不在 允许的协议白名单(self.allowed_schemes)中。
    3. 如果协议不被允许,则抛出一个 DisallowedRedirect 异常,中止重定向过程。这是防止安全漏洞的关键防线。
python 复制代码
    url = property(lambda self: self['Location'])
  • 只读属性 url :使用 property 装饰器创建了一个名为 url 的只读属性。当你访问 response.url 时,它会返回 Location 头部的值,即重定向的目标URL。这提供了一个非常方便和直观的访问方式。
python 复制代码
    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. 具体实现类:HttpResponseRedirectHttpResponsePermanentRedirect

这两个类非常简单,它们只做了一件事:继承基类并设置正确的HTTP状态码。

python 复制代码
class HttpResponseRedirect(HttpResponseRedirectBase):
    status_code = 302
  • 302 临时重定向 :HTTP状态码302表示所请求的资源暂时位于另一个URI下。客户端(如浏览器或搜索引擎爬虫)在遇到此重定向时,应该继续使用原始URL发起请求,因为这次重定向可能是临时的。
python 复制代码
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(),它内部就是创建这些类的实例。

等效的写法:

python 复制代码
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转换)又灵活(通过基类和不同状态码的子类)的重定向响应体系。

相关推荐
时序数据说7 小时前
国内开源时序数据库IoTDB介绍
大数据·数据库·物联网·开源·时序数据库·iotdb
BYSJMG7 小时前
计算机毕业设计选题:基于Spark+Hadoop的健康饮食营养数据分析系统【源码+文档+调试】
大数据·vue.js·hadoop·分布式·spark·django·课程设计
Databend7 小时前
CRC32 自包含退化现象分析
数据库
ITZHIHONH8 小时前
FastGPT源码解析 Agent知识库文本资料处理详解和代码分析
数据库·ai编程
子兮曰8 小时前
🔥告别ORM臃肿!用Bun.js原生SQLite打造极致轻量级数据库层
前端·sqlite·bun
小蒜学长9 小时前
基于Spring Boot的火灾报警系统的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端
福赖9 小时前
《MySQL基础——C 语言链接》
c语言·数据库·mysql
KIDAKN9 小时前
Redis 分布式锁
数据库·redis·分布式