资讯详情

一次 HTTP 请求,在 Django 里经历了什么?——中间件与请求生命周期,一次讲透

📅 2026/10/7 20:07:10 | 华诺云谱 👁 阅读
一次 HTTP 请求,在 Django 里经历了什么?——中间件与请求生命周期,一次讲透
你写 Django 应用每天都在处理请求。可你有没有停下来想过一个问题浏览器发出一个请求到你的视图函数view返回响应中间到底发生了什么大多数人只关心视图函数里写了什么。但真正让 Django 既灵活又强大的恰恰是视图函数之外的那一圈看不见的管道——中间件Middleware。搞懂中间件和请求的完整生命周期你才能理解为什么登录校验不用在每个视图里重复写、为什么 CSRF 防护能默默生效、为什么改个响应头能全局统一。这篇把这条看不见的管道拆给你看。一次请求完整走一圈先建立全局图。一个 Django 请求的生命周期大致是这条链路浏览器 └─ WSGI 服务器gunicorn / uvicorn └─ Django 中间件栈进自上而下 └─ URL 路由urls.py 匹配 └─ 视图函数view └─ 中间件栈出自下而上 └─ WSGI 返回 浏览器收到响应一句话概括请求要穿过一层层中间件才能到达视图响应返回时再逆着穿过这些中间件才能回到浏览器。这个结构像一颗洋葱——中间件是一层一层包着视图的洋葱皮。请求往里走时从外到内一层层剥响应往外走时从内到外一层层裹。中间件到底是干什么的中间件就是夹在请求和视图之间、对请求和响应做统一处理的钩子。它的价值在于解决一个所有 Web 框架都会遇到的问题有很多事是每个请求都要做一遍的可又不能塞进每个视图里重复写。比如身份认证每个请求进来先判断你是谁、有没有登录CSRF 防护检查表单提交是不是本网站发起的跨域CORS统一给响应加上允许跨域的头日志把每个请求的方法、路径、耗时记下来限流、压缩GZip、缓存……。这些事的特点是横切——它们不专属于某个视图而是横着切过所有视图。中间件就是为这类横切关注点准备的统一入口。没有它你就得在几十上百个视图里一遍遍地复制粘贴校验登录的代码。中间件是一堆钩子方法一个 Django 中间件就是一个普通的 Python 类只不过它定义了几个特定名字的方法框架会在请求的不同阶段自动调用它们钩子方法调用时机作用__init__服务器启动时初始化接收get_responseprocess_request视图执行前处理请求可提前返回响应process_view路由匹配后、视图执行前拿到 view 和参数可拦截process_exception视图抛异常时兜底处理异常process_template_response视图返回懒渲染响应时在模板渲染后处理process_response视图执行后处理响应可修改响应最关键的两个是process_request和process_responseprocess_request在请求往里走时被调用返回None就继续往下走返回HttpResponse就短路后面的中间件和视图都不执行了process_response在响应往外走时被调用每个中间件都可以对响应再加工最后返回响应。这里有个必须记住的顺序process_request按中间件列表从上到下执行process_response按从下到上执行。正是因为进出方向相反才形成了洋葱的结构。自己写一个秒懂看一个最小可运行的例子比看十段描述都管用。下面这个中间件给每个响应加一个自定义头并打印请求耗时importtimeclassSimpleMiddleware:def__init__(self,get_response):self.get_responseget_response# 记住下一层的入口def__call__(self,request):starttime.time()responseself.get_response(request)# 交给下一层最终到视图cost(time.time()-start)*1000response[X-Process-Time]f{cost:.2f}msprint(f{request.method}{request.path}-{cost:.2f}ms)returnresponse在settings.py里注册一下MIDDLEWARE[django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddleware,django.middleware.common.CommonMiddleware,django.middleware.csrf.CsrfViewMiddleware,django.contrib.auth.middleware.AuthenticationMiddleware,django.contrib.messages.middleware.MessageMiddleware,myapp.middleware.SimpleMiddleware,# 自定义的]那个__call__方法就是洋葱的一层它先记下时间再把请求交给self.get_response也就是下一层等下一层最终是视图跑完、响应传回来它再补上一刀加头、打日志最后返回。注意Django 的中间件在新式写法里核心是__call__老式写法process_request/process_response会被框架内部转换。但洋葱这个结构是两种写法共同的本质。它跟装饰器是失散多年的兄弟看到这个前置处理 调用 后置处理的结构你可能已经觉得眼熟了。没错中间件和 Python 装饰器是同一个思想的两个化身——都是在不侵入目标函数本身的前提下给目标函数包上一层逻辑。区别只在于作用范围装饰器包住一个函数中间件包住所有的视图。我之前聊过装饰器背后的闭包机制理解了那个再看中间件就是全局版的装饰器一点就透。而中间件这种按约定好的方法名被框架自动调用的风格也带着浓浓的鸭子类型味道——框架不管你的中间件类继承自谁只要你有__call__或那些钩子方法它就认你别问它是不是鸭子只要它叫得像鸭子——Python 的鸭子类型。一个常见的坑中间件顺序就是生死顺序正因为中间件是按列表顺序一层层包的MIDDLEWARE列表的顺序直接决定行为。举个最经典的例子AuthenticationMiddleware必须在SessionMiddleware之后。因为认证要读取 session 里的用户信息如果顺序反了认证中间件运行时 session 还没解析就会出错。所以记住一条心法越基础的中间件越要靠前。改中间件顺序前先想清楚谁依赖谁。结语框架的灵活来自这层可插拔的壳看懂中间件你就看懂了 Django 这类框架的架构哲学框架把请求处理切成一层层可插拔的壳你可以在不碰视图代码的前提下全局地加能力、改行为。视图只负责业务逻辑认证、日志、跨域、压缩这些横切的活交给中间件统一干。关注点分离代码才能又少又清晰——这就是中间件教给我们的架构课。下次再遇到每个接口都要做同一件事的需求先别急着复制粘贴想一想这能不能写成一个中间件想真正玩转 Django 的中间件、装饰器、闭包这些框架背后的 Python 机制光会用不够得懂 Python 的底层。推荐 B站【408实验室】的《Python 完全自学教程》把函数、闭包、类这些基本功打扎实框架的每一个魔法你都能看穿它的本质。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑