在 Django 中,中间件(Middleware)是处理 请求-响应过程中的钩子机制,位于 请求(request)和视图(view)之间,也可以位于 响应(response)和浏览器之间。通过中间件你可以对请求或响应进行统一的处理,如认证、日志、请求头修改、跨域处理、IP 限流等。

1.什么是中间件

中间件是一个类,它定义了一组钩子方法,用来在请求到达视图之前和响应返回客户端之前进行处理。

Django 会按顺序执行 MIDDLEWARE 列表中每一个中间件类。

2.中间件的生命流程

Browser → Request → Middleware → View → Response → Middleware → Browser

主要包括以下方法:

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

    def __call__(self, request):
        # 请求进入视图前处理
        response = self.get_response(request)
        # 响应返回客户端前处理
        return response


  def process_view(self, request, view_func, view_args, view_kwargs):
    pass  # 请求到达视图前执行(可拦截)

  def process_exception(self, request, exception):
    pass  # 视图发生异常时调用

  def process_template_response(self, request, response):
    pass  # 响应是 TemplateResponse 类型时调用

中间件钩子方法详细:

1. __call__(request)

作用:对所有请求前后做统一处理。

def __call__(self, request):
    print("请求到达前")
    response = self.get_response(request)
    print("响应返回后")
    return response

用场景:请求计时、响应日志、通用 token 验证等。

2.process_view(request, view_func, view_args, view_kwargs)

作用:在调用视图函数 之前,可以拦截、替换视图逻辑。

def process_view(self, request, view_func, view_args, view_kwargs):
    if request.path.startswith("/admin/") and not request.user.is_authenticated:
        return HttpResponse("未登录,禁止访问后台")
    return None

常用场景:权限校验、登录验证、请求重定向等。

3.process_exception(request, exception)

作用:当视图函数抛出异常时调用,可拦截处理异常。

def process_exception(self, request, exception):
    logger.error(f"异常发生:{exception}")
    return HttpResponse("服务器内部错误,请稍后再试")

常用场景:统一错误页面、自定义错误日志记录。

4.process_template_response(request, response)

作用:对视图返回的 TemplateResponse 进行修改,比如加数据、模板扩展。

def process_template_response(self, request, response):
    response.context_data['system_message'] = '系统运行良好'
    return response

常用场景:模板全局变量注入、统一提示框处理等。

示例:自定义中间件完整代码

from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse

class MyCustomMiddleware(MiddlewareMixin):
    def process_request(self, request):
        print(">>> 请求进入")

    def process_view(self, request, view_func, view_args, view_kwargs):
        print(f">>> 准备调用视图函数: {view_func.__name__}")

    def process_exception(self, request, exception):
        print(f">>> 捕获异常:{exception}")
        return HttpResponse("自定义错误处理:程序出错了")

    def process_template_response(self, request, response):
        print(">>> 模板响应处理")
        response.context_data['global_notice'] = '欢迎访问本站'
        return response

    def process_response(self, request, response):
        print(">>> 响应返回")
        return response

说明:从 Django 1.10 起推荐使用 __call__ 模式;如果继承 MiddlewareMixin,你就可以使用 process_xxx() 方式

注册中间件到项目

打开 settings.py 添加路径到 MIDDLEWARE

MIDDLEWARE = [
    ...
    'myapp.middleware.MyCustomMiddleware',
]
1、process_request(self,request)

2、process_view(self, request, callback, callback_args, callback_kwargs)

3、process_template_response(self,request,response)

4、process_exception(self, request, exception)

5、process_response(self, request, response)

以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户

1、process_request和process_response

当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者

中间件使用实例:

第一步导入

from django.utils.deprecation import MiddlewareMixin

第二步:自定义中间件

from django.utils.deprecation import MiddlewareMixin#
from django.shortcuts import HttpResponse
#
class Md1(MiddlewareMixin):
#
    def process_request(self,request):
        print("Md1请求")
 #
    def process_response(self,request,response):
        print("Md1返回")
        return response
#
class Md2(MiddlewareMixin):
#
    def process_request(self,request):
        print("Md2请求")
        #return HttpResponse("Md2中断")
    def process_response(self,request,response):#
        print("Md2返回")
        return response

第三步:在view中定义一个视图函数(index)

def index(request):

    print("view函数...")
    return HttpResponse("OK")

第四步:在settings.py的MIDDLEWARE里注册自己定义的中间件

运行结果:

Md1请求#
Md2请求#
view函数...#
Md2返回#
Md1返回#

由此总结一下:

  1. 中间件的process_request方法是在执行视图函数之前执行的。

  2. 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。

  3. 不同中间件之间传递的request都是同一个对象

多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

2、process_view

process_view(self, request, view_func, view_args, view_kwargs)

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表(无名分组分过来的值).

view_kwargs是将传递给视图的关键字参数的字典(有名分组分过来的值)。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

1. process_request(self, request)

调用时机

在 Django 接收到 HTTP 请求并封装为 HttpRequest 对象后、URL Resolver(URL 解析)之前,依次调用项目中各个中间件的 process_request

方法签名

def process_request(self, request: HttpRequest) -> Optional[HttpResponse]:
    ...
  • 参数

    • request:Django 原生 HttpRequest 对象。

  • 返回值

    • 返回 None:继续执行后续中间件或最终视图。

    • 返回 HttpResponse 实例:短路,后续中间件的 process_requestprocess_view、视图函数都不会再被调用,直接进入所有中间件的 process_response

典型用途

  • 统一鉴权:检查 Session、Token 或自定义 Header,若缺失或无效,直接返回 HttpResponseForbidden

  • 请求预处理:如给 request 附加属性、读取全局配置或打日志。

  • 跨域处理:早期设置 CORS 响应头(但推荐用专门包)。

class AuthMiddleware:
    def process_request(self, request):
        token = request.META.get("HTTP_X_API_TOKEN")
        if token != settings.EXPECTED_TOKEN:
            return HttpResponseForbidden("无效的 API Token")
        # else: 无需返回,继续后续中间件 & 视图


2. process_view(self, request, view_func, view_args, view_kwargs)

调用时机

在 URL 解析完毕、找到要调用的视图函数(或类视图 as_view() 生成的函数)之后,真正执行视图前。

方法签名

def process_view(
    self,
    request: HttpRequest,
    view_func: Callable,
    view_args: Tuple,
    view_kwargs: Dict
) -> Optional[HttpResponse]:
    ...

  • 参数

    • view_func:将要调用的视图函数(若是类视图,即该视图对应的可调用函数)。

    • view_argsview_kwargs:URL 解析后将被传给视图函数的位置参数和关键字参数。

  • 返回值

    • 返回 None:继续执行后续中间件或最终调用视图。

    • 返回 HttpResponse:短路,会调用视图本身,直接进入各中间件的 process_response

典型用途

  • 基于路由的权限/限流:不同路由使用不同权限检查或限流规则。

  • 视图预修改:动态替换或包装 view_func,比如给视图函数打补丁、注入共享资源。

  • 请求打标记:给 request 加上 request._start_time = time.time(),后面算耗时。

class TimingMiddleware:
    def process_view(self, request, view_func, view_args, view_kwargs):
        request._start_time = time.time()


3. process_template_response(self, request, response)

调用时机

视图函数执行并返回一个实现了 .render() 方法的响应对象(通常是 TemplateResponse 或其子类)后、调用 process_response 之前。

方法签名

def process_template_response(self, request: HttpRequest, response: TemplateResponse) -> TemplateResponse:
    ...

  • 参数

    • response:必须是 TemplateResponse 或同样支持延迟渲染的对象。

  • 返回值

    • 必须返回一个同样可渲染的响应对象(可以是修改后的原 response,也可以是一个全新实例)。

典型用途

  • 全局上下文处理:给所有模板响应注入公共上下文变量,如站点导航、用户信息。

  • 延迟渲染优化:在真正模板渲染前,动态切换模板引擎或主题。

class CommonContextMiddleware:
    def process_template_response(self, request, response):
        # 在所有模板上下文里添加 site_name
        response.context_data['site_name'] = "我的站点"
        return response

4. process_exception(self, request, exception)

调用时机

当视图函数或中间件的 process_view 抛出未捕获的异常时,Django 会倒序调用已经过的中间件的 process_exception

  • 注意:如果 process_exception 返回 HttpResponse,则会停止后续异常处理逻辑,直接进入各中间件的 process_response

  • 如果都返回 None,则继续 Django 默认的错误处理(如 DEBUG 时展示追踪页)。

方法签名

def process_exception(self, request: HttpRequest, exception: Exception) -> Optional[HttpResponse]:
    ...
  • 参数

    • exception:视图或前置中间件抛出的异常实例。

  • 返回值

    • 返回 HttpResponse:用此响应替代原本的错误页面或异常继续抛出;

    • 返回 None:交由 Django 或其他中间件继续处理。

典型用途

  • 全局日志:将异常信息上报到日志系统或外部监控(如 Sentry)。

  • 自定义错误页:捕获特定异常类型后返回用户友好的错误页面。

class ExceptionLoggingMiddleware:
    def process_exception(self, request, exception):
        logger.error("Unhandled exception", exc_info=exception)
        # 不返回 HttpResponse,继续 Django 默认流程


5. process_response(self, request, response)

调用时机

整个请求—视图—渲染流程结束后,得到一个 HttpResponse,倒序经过所有中间件的 process_response

方法签名

def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
    ...
  • 参数

    • response:视图或者 process_exceptionprocess_template_response 返回的最终响应。

  • 返回值

    • 必须返回一个 HttpResponse 对象:可以是原对象、修改后的,或全新实例。

典型用途

  • 统一响应头:添加/修改 CORS、缓存、加密签名等 HTTP Header。

  • 后置日志:记录请求处理时长、HTTP 状态码、访问 IP 等。

  • 内容压缩:对 HTML/JSON 响应进行 gzip 压缩(内建 GZipMiddleware 即此实现)。

class ResponseHeaderMiddleware:
    def process_response(self, request, response):
        response['X-Powered-By'] = 'Django'
        return response


中间件调用顺序图示

请求进来
   ↓
┌─ process_request (M1)
│
├─ process_request (M2)
│
└─ process_request (M3)
   ↓
URL 解析 → 视图函数
   ↓
┌─ process_view (M1)
│
├─ process_view (M2)
│
└─ process_view (M3)
   ↓
视图执行
   ↓
视图返回 TemplateResponse?
   ├─ Yes → process_template_response (M1→M3)
   └─ No
   ↓
       ↓(或上)
┌─ process_response (M3)
│
├─ process_response (M2)
│
└─ process_response (M1)
   ↓
返回客户端

  • 异常分支:若视图或 process_view 抛异常,则倒序调用各中间件的 process_exception,如有返回则接着走 process_response

视图或 process_view 抛 Exception
   ↓
┌─ M3.process_exception(request, exception)
│   ├─ 返回 HttpResponse? → 是 → 跳到 ↓③
│   └─ 返回 None      → 继续
│
├─ M2.process_exception(request, exception)
│   ├─ 返回 HttpResponse? → 是 → 跳到 ↓③
│   └─ 返回 None      → 继续
│
└─ M1.process_exception(request, exception)
    ├─ 返回 HttpResponse? → 是 → ↓③
    └─ 返回 None      → ↓①

① 默认异常处理(DEBUG:追踪;生产:500 页面)
   ↓
② Django 得到一个 HttpResponse(异常页或中间件产出)
   ↓
③ 依次调用:
    M3.process_response(request, response)
    M2.process_response(request, response)
    M1.process_response(request, response)
   ↓
返回最终 response 给客户端