首页 > 其他分享 >Django框架--中间件

Django框架--中间件

时间:2024-11-26 16:43:47浏览次数:7  
标签:__ 请求 get -- request 中间件 Django response

一、介绍

1. 中间件的定义

Django 中间件是一个轻量级、底层的“插件”系统,用于全局地修改 Django 的输入或输出。每个中间件组件可以对请求进行处理或对响应进行处理,或者同时处理二者。

2. 中间件的功能

中间件可以执行的操作包括:

  • 请求预处理:在视图函数处理请求之前,执行一些前置操作(如请求验证、设置请求参数等)。
  • 响应后处理:在视图函数处理完请求后,对生成的响应进行处理(如设置 HTTP 头、压缩响应内容等)。
  • 请求/响应异常处理:捕捉到处理请求或响应过程中的异常。
3. 中间件的结构

每个中间件组件需要实现以下方法之一或全部:

  • __init__(self, get_response): 初始化中间件实例。get_response 是一个指向下一个中间件的调用链或最终视图的函数。
  • __call__(self, request): 在每个请求上调用,用于处理请求和生成响应。通常在这里调用 self.get_response(request) 将请求传递到下一个中间件或视图。
4. 中间件的调用流程
  • 请求流程:当请求到达 Django 时,它按照在 settings.py 中定义的中间件顺序,从上到下依次通过各个中间件的 __call__ 方法。
  • 响应流程:一旦请求到达视图并由视图生成响应,响应将按照中间件的相反顺序回传,允许每个中间件对响应进行修改或处理。
5. 中间件的配置

settings.pyMIDDLEWARE 配置列表中定义项目使用的中间件。中间件的执行顺序由它们在这个列表中的顺序决定。

6. 示例:自定义语言中间件

一个简单的自定义中间件示例,用于根据请求头 Accept-Language 动态设置语言环境。

from django.utils import translation

class LanguageMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        language = request.headers.get('Accept-Language', None)
        if language == 'zh-hans':
            translation.activate('zh-hans')
            print("使用中文")
        else:
            translation.activate('en')
            print("使用英文")
        response = self.get_response(request)
        return response
一、中间件的初始化过程 (__init__ 方法)
def __init__(self, get_response):
    self.get_response = get_response
  • __init__(self, get_response): 这是中间件的构造函数。当 Django 启动并加载中间件时,它会为每个中间件实例传递一个 get_response 参数。这个参数是一个函数,指向中间件链中下一个中间件的 __call__ 方法,或者在链条的末端时,指向最终的视图函数。
  • self.get_response = get_response: 这行代码将传入的 get_response 函数保存为中间件实例的一个属性。这样做使得在处理请求的过程中,当前中间件可以通过调用 self.get_response(request) 来继续执行请求处理链,将请求传递给下一个中间件或视图。
二、请求处理过程 (__call__ 方法)
def __call__(self, request):
    language = request.headers.get('Accept-Language', None)
    if language == 'zh-hans':
        print("使用中文")
    else:
        translation.activate('en')
        print("使用英文")

    return self.get_response(request)
  • 请求到达时:当一个请求到达 Django 时,如果 LanguageMiddleware 是中间件链中的一部分,Django 将自动调用它的 __call__ 方法,并将当前的请求对象 (request) 传递进来。
  • 语言检测和设置:
    • language = request.headers.get('Accept-Language', None): 这行代码尝试从请求头中获取 Accept-Language 字段的值。这是一个 HTTP 标准头部,用于指明用户的语言偏好。
  • 传递请求:return self.get_response(request) 这行代码调用前面在 __init__ 方法中保存的 get_response 函数,将控制权和修改后的请求传递给中间件链中的下一个中间件或直接到视图。这保证了请求继续在中间件链中流动,直到最终被视图处理。

这个 LanguageMiddleware 的工作流程典型地展示了 Django 中间件如何拦截和处理 HTTP 请求,以及如何在处理完毕后将请求继续传递。每个中间件都可以在请求到达视图之前或视图返回响应之后执行某些操作,这提供了极大的灵活性和控制力,使得 Django 的中间件架构非常强大。

7. 中间件的注意事项

● 中间件的执行顺序极其重要,因为它会影响请求的处理逻辑。

● 在中间件中修改请求或响应时需要小心,以免影响到后续中间件或视图的行为。

● 中间件应尽量保持轻量,避免执行耗时的操作,以免影响应用的响应时间。

二、中间件调用流程

(一) 流程

1. 示例背景

假设你的 Django 项目有三个中间件:

  1. MiddlewareA
  2. MiddlewareB
  3. MiddlewareC

并且有一个视图函数 view_function

2. 初始化阶段

当 Django 项目启动时,它会按照 settings.py 中的 MIDDLEWARE 配置列表(配置为 A、B、C)来创建和设置中间件。初始化阶段如下:

  1. 创建 MiddlewareA 实例
    • Django 调用 MiddlewareA.__init__(get_response=MiddlewareB.__call__)
    • 这里 get_response 是指向下一个中间件 MiddlewareB__call__ 方法。
  1. 创建 MiddlewareB 实例
    • Django 调用 MiddlewareB.__init__(get_response=MiddlewareC.__call__)
    • get_response 现在指向 MiddlewareC__call__ 方法。
  1. 创建 MiddlewareC 实例
    • Django 调用 MiddlewareC.__init__(get_response=view_function)
    • get_response 指向视图函数 view_function,这是请求处理链的最后一环。
3. 请求处理阶段

当一个请求到达 Django 服务器时,Django 会创建一个 HttpRequest 对象,并开始通过中间件链进行处理,如下所示:

  1. 请求首先到达 MiddlewareA
    • 调用 MiddlewareA.__call__(request)
    • MiddlewareA 处理请求(如检查请求头、设置某些参数等)。
    • 调用 self.get_response(request) 继续将请求传递到 MiddlewareB。
  1. 请求继续到 MiddlewareB
    • 调用 MiddlewareB.__call__(request)
    • MiddlewareB 进行其处理。
    • 调用 self.get_response(request) 将请求传递到 MiddlewareC。
  1. 请求最后到达 MiddlewareC
    • 调用 MiddlewareC.__call__(request)
    • MiddlewareC 完成处理。
    • 调用 self.get_response(request) 将请求传递给视图函数 view_function
  1. 视图函数处理请求
    • 视图函数 view_function 处理请求并生成一个响应 HttpResponse
4. 响应处理阶段

生成的响应会沿着相同的中间件链逆向传回:

  1. 响应从视图返回到 MiddlewareC
    • 如果 MiddlewareC 需要对响应进行处理或修改,它在这里执行。
  1. 响应传回到 MiddlewareB
    • MiddlewareB 对响应进行进一步的处理或修改。
  1. 最后响应返回到 MiddlewareA
    • MiddlewareA 进行最终的处理或修改。
  1. 响应返回给用户
    • 响应完成后,由 Django 返回给发起请求的客户端。

三、场景

(一) 根据不同 az 访问不同后端视图 url 但前端 url 不变

根据请求中的自定义头部 Az-Id 来决定是否对请求的 URL 进行重写。这种中间件可以用于动态修改请求路径,以便根据某些条件路由到不同的处理逻辑或服务。

class URLRewriteMiddleware(MiddlewareMixin):
    def __init__(self, get_response):
        super().__init__(get_response)
        self.get_response = get_response

    def process_request(self, request):
        # 获取自定义头部 'az_id'
        az_id = request.headers.get('Az-Id')
        az_obj = CloudOsAz.objects.filter(az_id=az_id).first()
        supplier = "test"
        if az_obj and az_obj.supplier:
            supplier = az_obj.supplier

        # 根据头部值定义重定向逻辑
        if supplier != "test": 
            old_path = request.path
            new_path = old_path.replace('/url/v1/', '/url/v2/')
            request.path = new_path
            request.path_info = new_path

        logger.info(f'req rewrite url: az_id: {az_id}, supplier: {supplier}, url: {request.path_info}')
1. 代码逻辑
  1. 初始化
def __init__(self, get_response):
    super().__init__(get_response)
    self.get_response = get_response
    • 这里调用了 super().__init__(get_response),这在使用 MiddlewareMixin 时是多余的,因为 MiddlewareMixin__init__ 方法已经完成了相关初始化。
    • self.get_response 被赋值为传入的 get_response 参数,这是中间件链中下一个处理函数的引用。
  1. 处理请求
def process_request(self, request):
        # 获取自定义头部 'az_id'
        az_id = request.headers.get('Az-Id')
        az_obj = CloudOsAz.objects.filter(az_id=az_id).first()
        supplier = "test"
        if az_obj and az_obj.supplier:
            supplier = az_obj.supplier

        # 根据头部值定义重定向逻辑
        if supplier != "test":  
            old_path = request.path
            new_path = old_path.replace('/url/v1/', '/url/v2/')
            request.path = new_path
            request.path_info = new_path

        logger.info(f'req rewrite url: az_id: {az_id}, supplier: {supplier}, url: {request.path_info}')
    • 获取头部:从请求头中获取 Az-Id 的值。
    • 查询数据库:使用 az_id 查询 CloudOsAz 表中的记录,得到供应商信息(supplier)。如果找到记录且有供应商信息,就更新 supplier
    • 重写 URL:如果 supplier 不等于 "test",则将请求的路径中的 /url/v1/ 部分替换为 /url/v2/,并更新 request.pathrequest.path_info。这样请求将会被重定向到新的路径。

标签:__,请求,get,--,request,中间件,Django,response
From: https://www.cnblogs.com/Studywith/p/18570482

相关文章

  • 百家号批量删除文章脚本
    补一句,百家号真恶心!functionsleep(ms){returnnewPromise(resolve=>setTimeout(resolve,ms));}asyncfunctionexecuteTasks(){while(1==1){awaitsleep(5000);constmouseOverEvent=newMouseEvent('m......
  • 02-SDL2使用(一)
    1.新建一个窗体并添加事件监听与响应SDL_Init(),首先是按照需求对SDL相关子系统进行初始化,在程序最后退出之前需要使用SDL_Quit()清理所有初始化的子系统。SDL_CreateWindow()创建一个窗体,SDL_DestroyWindow()销毁窗体。SDL_Event定于一个事件,SDL_PollEvent()当前挂起事件的轮......
  • php毕业设计购物商城在线购物系统日用品购物商城手工艺系统日用品系统手工艺网站php+m
    一,功能介绍        前台主要包括网站首页、商品推荐、最新商品、新闻咨询、商品分类、商品资讯、评论、登录、注册、加入购物车、结算、个人中心等功能模块商品推荐、最新商品在商品推荐、最新商品模块,用户可以查看全部商品信息,选择商品进行添加购物车等操作,购物......
  • JavaScript 类型转换
    基础概念什么是类型转换JavaScript是一种动态弱类型语言,其类型转换机制允许开发者灵活地处理不同数据类型之间的交互。类型转换是指将一个值从一种数据类型转换为另一种数据类型的过程,在JavaScript中主要分为两种方式:隐式类型转换:由JavaScript引擎自动执行,例如在算术运......
  • 重温经典,一网万游:在线红白机FC游戏平台:webgame.one
    前言还记得小时候守在电视机前,手握红白机手柄,沉浸在《魂斗罗》紧张刺激的战斗、《超级马里奥兄弟》奇妙的冒险世界,或是与小伙伴一起在《坦克大战》里并肩作战的美好时光吗?那些经典的FC游戏,承载着我们童年最纯真的快乐与回忆。如今,有一个名为webgame.one的在线FC游戏平台......
  • JavaScript 条件语句详解
    JavaScript条件语句概述条件语句的作用在JavaScript编程中,条件语句是控制程序流程的核心机制。它们使程序能够根据特定条件执行不同代码块,从而实现灵活的决策逻辑。通过使用if、if-else和switch等语句,开发者可以根据变量值或表达式结果动态地改变代码执行路径,使得程序能够......
  • 微课教学优势
    微课教学优势灵活性高,微课可以随时随地进行学习,适应不同学习者的时间安排,提高学习效率。针对性强,微课内容通常聚焦于一个具体主题,有助于学习者快速掌握特定知识点。互动性好,微课平台通常提供互动功能,如讨论区和即时反馈,增强学习体验和效果。微课与传统课程对比课程时长差异,微......
  • STM32和STM8开发工具、常用软件和开发环境汇总
    文章目录一、前言二、KeilC51软件三、KeilMDK-ARM四、STM32CubeMX及HAL库五、STM32CubeIDE六、STM8CubeMX七、STM32ST-LINKUtility一、前言整理一些常见的STM32/STM8开发所需要的安装包和工具。可以分别去官网下载最新的安装包。也可以通过关注【小康师兄】......
  • AbMole| JNJ-42041935(CAS号1193383-09-3;目录号M8963)
    JNJ-42041935是一种高效的,竞争性的,选择性脯氨酰羟化酶PHD抑制剂,对于PHD1,PHD2andPHD3的pKi值分别为7.91±0.04,7.29±0.05和7.65±0.09。生物活性JNJ-42041935是一种有效的,2-氧戊二酸竞争性,可逆性和选择性PHD酶抑制剂。JNJ-42041935是PHD2181-417最有效的抑制剂,其pIC50......
  • leetcode78 子集
    leetcode78子集思路:深度优先搜索回溯分析此类问题可以先用树形结构模拟代码逻辑。那么根据这个解答树,首先我们的回溯搜索函数应该由这么几部分组成将搜索获得的答案加入到res中。for循环遍历搜索下一个元素(比如在初始列表为空的时候,第一位可以选1,2,3显然需要通过循环实现)......