Django中间件的源码解析流程(上)——中间件载入的前置

news2024/11/13 8:03:53

目录

1. ​前言​

2. 请求的入口

3. 中间件加载的入口

4. 源码中的闭包实现

5. 最后


1. 前言

哈喽,大家好,我是小K,今天咋们分享的内容是:在学会Django中间件之后, 我们继续深入底层源码。

在执行中间件时请求到来总是从前往后逐一匹配,但当响应返回时,执行的中间件顺序往往是反着执行的。

在Django中间件中,采用了多层闭包的形式,以来达到逐一执行中间件,本篇文章主要是从请求的入口开始,简单介绍一下前置。

如果还不会使用中间件的小伙伴可以跳转到这里:

Django之五种中间件定义类型

2. 请求的入口

在同步请求中,请求的入口其实就是 wsgi.py 文件, 不清楚的可以跳转这里,看第2点:

Django源码之路由匹配(下)——图解逐步分析底层源码

3. 中间件加载的入口

在请求到来时,最后返回的是一个WSGIHandler的一个对象

application = get_wsgi_application()


def get_wsgi_application():
    django.setup(set_prefix=False)
    return WSGIHandler()


class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()

在加载对象时,肯定是少不了执行__init__的初始化方法的

self.load_middleware()   # 这其实就是加载中间件的方法

在执行load_middleware()函数时,首先是在自己的类中寻找,如果没有就去父类中寻找

显然,这里的代码是需要我们去父类BaseHandler类中寻找的


这里BaseHandler类和load_middleware的源码:

class BaseHandler:
    _view_middleware = None
    _template_response_middleware = None
    _exception_middleware = None
    _middleware_chain = None

    def load_middleware(self, is_async=False):
        """
        Populate middleware lists from settings.MIDDLEWARE.

        Must be called after the environment is fixed (see __call__ in subclasses).
        """
        self._view_middleware = []
        self._template_response_middleware = []
        self._exception_middleware = []

        get_response = self._get_response_async if is_async else self._get_response
        handler = convert_exception_to_response(get_response)
        handler_is_async = is_async
        for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)
            middleware_can_sync = getattr(middleware, "sync_capable", True)
            middleware_can_async = getattr(middleware, "async_capable", False)
            if not middleware_can_sync and not middleware_can_async:
                raise RuntimeError(
                    "Middleware %s must have at least one of "
                    "sync_capable/async_capable set to True." % middleware_path
                )
            elif not handler_is_async and middleware_can_sync:
                middleware_is_async = False
            else:
                middleware_is_async = middleware_can_async
            try:
                # Adapt handler, if needed.
                adapted_handler = self.adapt_method_mode(
                    middleware_is_async,
                    handler,
                    handler_is_async,
                    debug=settings.DEBUG,
                    name="middleware %s" % middleware_path,
                )
                mw_instance = middleware(adapted_handler)
            except MiddlewareNotUsed as exc:
                if settings.DEBUG:
                    if str(exc):
                        logger.debug("MiddlewareNotUsed(%r): %s", middleware_path, exc)
                    else:
                        logger.debug("MiddlewareNotUsed: %r", middleware_path)
                continue
            else:
                handler = adapted_handler

            if mw_instance is None:
                raise ImproperlyConfigured(
                    "Middleware factory %s returned None." % middleware_path
                )

            if hasattr(mw_instance, "process_view"):
                self._view_middleware.insert(
                    0,
                    self.adapt_method_mode(is_async, mw_instance.process_view),
                )
            if hasattr(mw_instance, "process_template_response"):
                self._template_response_middleware.append(
                    self.adapt_method_mode(
                        is_async, mw_instance.process_template_response
                    ),
                )
            if hasattr(mw_instance, "process_exception"):
                # The exception-handling stack is still always synchronous for
                # now, so adapt that way.
                self._exception_middleware.append(
                    self.adapt_method_mode(False, mw_instance.process_exception),
                )

            handler = convert_exception_to_response(mw_instance)
            handler_is_async = middleware_is_async

        # Adapt the top of the stack, if needed.
        handler = self.adapt_method_mode(is_async, handler, handler_is_async)
        # We only assign to this when initialization is complete as it is used
        # as a flag for initialization being complete.
        self._middleware_chain = handler

 ok,我们现在着重来分析load_middleware的源码

4. 源码中的闭包实现

先来看看什么是闭包:

Python奇幻之旅(从入门到入狱基础篇)——附相关资料【中】-CSDN博客

这篇文章里面有一部分介绍了闭包和装饰器

现在来看具体的闭包实现函数:

def convert_exception_to_response(get_response):
    if iscoroutinefunction(get_response):

        @wraps(get_response)
        async def inner(request):
            try:
                response = await get_response(request)
            except Exception as exc:
                response = await sync_to_async(
                    response_for_exception, thread_sensitive=False
                )(request, exc)
            return response

        return inner
    else:
        @wraps(get_response)
        def inner(request):
            try:
                response = get_response(request)
            except Exception as exc:
                response = response_for_exception(request, exc)
            return response

        return inner

最后返回了一个inner函数, 而这个inner调用的是get_response()

最后都被封装进了handler里面

5. 最后

本文只是简单介绍了一下中间件加载的位置,下一篇文章将采用长篇的形式详细讲解中间件是如何通过闭包的形式载入的。今天就先到这里啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1613210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Golang那些违背直觉的编程陷阱

目录 知识点1:切片拷贝之后都是同一个元素 知识点2:方法集合决定接口实现,类型方法集合是接口方法集合的超集则认定为实现接口,否则未实现接口 切片拷贝之后都是同一个元素 package mainimport ("encoding/json"&quo…

[Kubernetes] etcd的集群基石作用

文章目录 1. 配置存储2. 数据一致性3. 服务发现与协调4. 集群状态中枢5. 集群稳定性 1. 配置存储 etcd作为一个高度可靠的分布式键值存储系统,存储了Kubernetes集群的完整配置和状态数据。集群的元数据,包括节点信息、命名空间、部署、副本集、服务、持…

【leetcode面试经典150题】65. 旋转链表(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主,题解使用C语言。(若有使用其他语言的同学也可了解题解思路,本质上语法内容一致&…

Mac电池管理软件 Batteries for Mac v2.2.9直装版

Batteries for Mac,作为一款专为Mac用户设计的电池管理软件,以其强大的功能和智能的监测机制,为用户提供了便捷、高效的电池使用体验。 Batteries for Mac(Mac电池)v2.2.9直装版下载 首先,Batteries for Mac具备实时电池监测功能&…

在protobuf里定义描述rpc方法的类型

service UserServiceRpc //在test.proto中定义 { rpc Login(LoginRequest)returns(LoginResponse); rpc GetFriendLists(GetFriendListRequest)returns(GetFriendListResponse); } test.proto文件生成test.pb.cc protoc test.proto --cpp_out./ 将生成的…

前端工程化01-复习jQuery当中的AJAX

4.1、基础概念 什么是服务器 一台存储网站内容、网站文件的电脑 什么是资源 网站中使用的文件(html、css、图片、…)这些东西就叫做资源数据也是服务器上的资源,而且是一个网站的灵魂 客户端 客户端应该指上网的设备但是在前端开发中&a…

微软如何打造数字零售力航母系列科普01 --- Azure顾问(AZURE Advisor)简介

Azure顾问(AZURE Advisor)简介 目录 一、什么是AZURE顾问(AZURE Advisor)? 二、常见问题 三、接下来的步骤 一、什么是AZURE顾问? AZURE顾问是一种数字云助手,可帮助您遵循最佳实践来优化Az…

【QT进阶】Qt http编程之用户登录注册功能实现

往期回顾 【QT进阶】Qt http编程之http与https简单介绍-CSDN博客 【QT进阶】Qt http编程之后端API测试工具postman使用介绍-CSDN博客 【QT进阶】Qt http编程之http相关类的简单介绍-CSDN博客 【QT进阶】Qt http编程之用户登录注册功能实现 一、最终效果展示 重点在逻辑实现&a…

分类神经网络2:ResNet模型复现

目录 ResNet网络架构 ResNet部分实现代码 ResNet网络架构 论文原址:https://arxiv.org/pdf/1512.03385.pdf 残差神经网络(ResNet)是由微软研究院的何恺明、张祥雨、任少卿、孙剑等人提出的,通过引入残差学习解决了深度网络训练中的退化问题&#xff…

[Spring Cloud] (4)搭建Vue2与网关、微服务通信并配置跨域

文章目录 前言gatway网关跨域配置取消微服务跨域配置 创建vue2项目准备一个原始vue2项目安装vue-router创建路由vue.config.js配置修改App.vue修改 添加接口访问安装axios创建request.js创建index.js创建InfoApi.js main.jssecurityUtils.js 前端登录界面登录消息提示框 最终效…

【八股】Spring Boot

SpringBoot是如何实现自动装配的? 首先,SpringBoot的核心注解SpringBootApplication里面包含了三个注解,SpringBootConfigurationEnableAutoConfigurationComponentScan,其中EnableAutoConfiguration是实现自动装配的注解&#x…

VUE运行找不到pinia模块

当我们的VUE运行时报错Module not found: Error: Cant resolve pinia in时 当我们出现这个错误时 可能是 没有pinia模块 此时我们之要下载一下这个模块就可以了 npm install pinia

AD高速板设计-DDR(笔记)

【一】二极管 最高工作频率: 定义:二极管的最高工作频率,即二极管在电路中能够正常工作的最高频率。常见的硅二极管的最高工作频率通常在几十MHz到几百MHz之间。在高频下,二极管可能无法有效地阻止反向电流,但也不会…

C# WPF布局

布局&#xff1a; 1、Grid: <Window x:Class"WpfApp2.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d"http://schemas.microsoft.com…

【大语言模型LLM】-使用大语言模型搭建点餐机器人

关于作者 行业&#xff1a;人工智能训练师/LLM 学者/LLM微调乙方PM发展&#xff1a;大模型微调/增强检索RAG分享国内大模型前沿动态&#xff0c;共同成长&#xff0c;欢迎关注交流… 大语言模型LLM基础-系列文章 【大语言模型LLM】-大语言模型如何编写Prompt?【大语言模型LL…

地质图、地质岩性数据、地质灾害分布、土壤理化性质数据集、土地利用数据、土壤重金属含量分布、植被类型分布

地质图是将沉积岩层、火成岩体、地质构造等的形成时代和相关等各种地质体、地质现象&#xff0c;用一定图例表示在某种比例尺地形图上的一种图件。 是表示地壳表层岩相、岩性、地层年代、地质构造、岩浆活动、矿产分布等的地图的总称。 地质图的编制多以实测资料为基础&#xf…

Eclipse+Java+Swing实现学生信息管理系统-TXT存储信息

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 存储方式&#xff1a;Txt文件存储 2.技术选型 JavaSwingTxt 3.功能模块 4.工程结构 5.系统功能 1.系统登录 管理员可以登录系统。 2.教师-查看学生…

初学者如何选择ARM开发硬件?

1&#xff0e; 如果你有做硬件和单片机的经验,建议自己做个最小系统板&#xff1a;假如你从没有做过ARM的开发&#xff0c;建议你一开始不要贪大求全&#xff0c;把所有的应用都做好&#xff0c;因为ARM的启动方式和dsp或单片机有所不同&#xff0c;往往会碰到各种问题&#xf…

【天龙怀旧服】攻略day7

关键字&#xff1a; 新星1.49、金针渡劫、10灵 1】新星&#xff08;苍山破煞&#xff09; 周三周六限定副本&#xff0c;19.00-24.00 通常刷1.49w&#xff0c;刷149点元佑碎金 boss选择通常为狂鬼难度&#xff0c;八风不动即放大不选&#xff0c;第二排第一个也不选&#xf…

【Hadoop】- MapReduce YARN的部署[8]

目录 一、部署说明 二、集群规划 三、MapReduce配置文件 四、YARN配置文件 五、分发配置文件 六、集群启动命令 七、查看YARN的WEB UI 页面 一、部署说明 Hadoop HDFS分布式文件系统&#xff0c;我们会启动&#xff1a; NameNode进程作为管理节点DataNode进程作为工作节…