Django中间件探索:揭秘中间件在Web应用中的守护角色与实战应用

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、默认中间件
    • [1. 中间件作用](#1. 中间件作用)
    • [2. 中间件执行顺序](#2. 中间件执行顺序)
  • 二、自定义中间件
    • [1. 钩子方法的种类](#1. 钩子方法的种类)
    • [2. 自定义中间件](#2. 自定义中间件)
      • [a. 自定义中间件并注册](#a. 自定义中间件并注册)
      • [b. 提供一个测试中间件效果的正确视图](#b. 提供一个测试中间件效果的正确视图)
      • [c. 提供一个测试中间件效果的错误视图](#c. 提供一个测试中间件效果的错误视图)
      • [d. 提供一个测试中间件效果的模板视图](#d. 提供一个测试中间件效果的模板视图)

前言

Django中间件 是Web应用中的隐形守护者,负责在请求与响应之间执行关键任务。本文将解析Django默认中间件的作用 ,并教你如何编写和注册自定义中间件 。通过实际案例,你将了解中间件在视图处理、错误处理和模板渲染中的作用。


一、默认中间件

1. 中间件作用

Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,全局修改Django的输入或输出。

中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。

因为改变的是全局,所以需要谨慎使用,用不好会影响到性能.
作用: 在不改 django框架源代码的基础上 新增全局的扩展功能

  • 本质就是个装饰器 - - - 中间件只需要添加一次, 所有的接口都生效

2. 中间件执行顺序

  • 如果你想修改请求,例如被传送到view 中的**HttpRequest对象。 或者你想修改view返回的 HttpResponse**对象,这些都可以通过中间件来实现。
  • 可能你还想在view 执行之前做一些操作,这种情况就可以用 middleware来实现。

Django默认的中间件 :(在django 项目的settings 模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图)

python 复制代码
#settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    # 为request/response提供了几种xss脚本过滤的安全改进,无它不安全
    'django.contrib.sessions.middleware.SessionMiddleware',
    # 开启session会话支持,无它无session
    'django.middleware.common.CommonMiddleware',
    # 基于APPEND_SLASH和PREPEND_WWW的设置来重写URL,
    # 如果APPEND_SLASH设为True,并且初始URL 没有以斜线结尾以及在URLconf 中没找到对应定义,这时形成一个斜线结尾的新URL;
    # 如果PREPEND_WWW设为True,前面缺少 www.的url将会被重定向到相同但是以一个www.开头的ur
    
    'django.middleware.csrf.CsrfViewMiddleware',
    # 添加跨站点请求伪造的保护,通过向POST表单添加一个隐藏的表单字段,并检查请求中是否有正确的值,无它无csrf保护
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    # 在视图函数执行前向每个接收到的user对象添加HttpRequest属性,表示当前登录的用户,无它用不了request.user
    'django.contrib.messages.middleware.MessageMiddleware',
    # 开启基于Cookie和会话的消息支持,无它无message
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    # 对点击劫持的保护
]

二、自定义中间件

1. 钩子方法的种类

django中默认给咱们提供了几个中间件,如果在过程中开发者想自己对请求和响应做出特殊处理,需要自己定义一个中间件,自定义的中间件需要继承 django.utils.deprecation.MiddlewareMixin这个类。并重写对应的方法。

中间件中重写的5个方法:

python 复制代码
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对象,则直接将该对象返回给用户。

2. 自定义中间件

a. 自定义中间件并注册

自定义中间件 示例代码如下:

python 复制代码
# customMiddleware.py
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin


class CustomMiddleware(MiddlewareMixin):

    def process_request(self, request):
        """
        处理请求前: 在每个请求上,request对象产生之后,url匹配之前调用,返回None或HttpResponse对象
        """
        print('before request=====', request)

    def process_view(self, request, view_func, *view_args, **view_kwargs):
        """
        :param view_func: Django即将使用的视图函数,它是实际的函数对象,而不是函数的名称作为字符串
        :param view_args: 将传递给视图的位置参数的列表
        :param view_kwargs: 将传递给视图的关键字参数的字典;
               view_args和view_kwargs都不包含第一个视图参数(request)
        """
        # 处理视图前:在每个请求上,url匹配之后,视图函数调用之前调用,返回None或HttpResponse对象
        print('before view=======')

    def process_template_response(self, request, response):
        # 在视图函数执行完后立即执行的, 执行 该 函数有一个前提条件,那就是视图函数返回的对象是一个 TemplateResponse 对象或等价方法, 直接返回render函数无效)
        print("render template=======")
        return response

    def process_exception(self, request, exception):
        # 这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象
        print("raise exception=======")
        return HttpResponse(exception)

    def process_response(self, request, response):
        # 处理响应后:视图函数调用之后,所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象
        print('after response=======', response)
        return response

在process_response中可以实现将返回数据修改操作 ,示例代码(此代码只可以响应drf的Response有效,因为普通HttpResponse中没有data属性):

python 复制代码
from django.utils.encoding import force_str, force_bytes
import json

def process_response(self, request, response):
    if response['Content-Type'] == 'application/json':
        # 解码JSON数据
        data = json.loads(force_str(response.content))
        # 修改数据
        data['modified_key'] = 'modified_value'
        # 重新编码JSON数据
        response.content = force_bytes(json.dumps(data))
    return response

注册中间件:

django 项目的 settings 模块中,在 MIDDLEWARE_CLASSES 变量中添加自定义中间件

python 复制代码
MIDDLEWARE = [
	# 添加自定义的中间件---CustomMiddleware
    'app.customMiddleware.CustomMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    ......
]

b. 提供一个测试中间件效果的正确视图

b.提供一个测试中间件效果的正确视图:

python 复制代码
# views.py
from rest_framework.views import APIView
from django.http import HttpResponse


# Create your views here.

class IndexView(APIView):
    def get(self, request):
        print("IndexView======================")
        return HttpResponse("Hello Index GET")

当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求会依次穿过所有中间件的process_request方法,最后到达views的函数中,views函数处理后,在依次穿过所有中间件的process_response方法,最后返回给请求者。
中间件执行结果展示:

访问路径:http://localhost:8000/app/index/

python 复制代码
before request===== <WSGIRequest: GET '/app/index/'>
before view=======
IndexView======================
after response======= <HttpResponse status_code=200, "text/html; charset=utf-8">
[16/Jun/2024 19:55:45] "GET /app/index/ HTTP/1.1" 200 15

c. 提供一个测试中间件效果的错误视图

c.提供一个测试中间件效果的错误视图:

python 复制代码
# views.py
from rest_framework.views import APIView
from django.http import HttpResponse


# Create your views here.

class IndexView(APIView):
    def get(self, request):
        print("IndexView======================")
        3/0
        return HttpResponse("Hello Index GET")

此时,视图发生异常, 会执行中间件的 process_exception方法,而在该方法中,将异常信息作为响应返回,因此,页面显示"division by zero"
中间件执行结果展示:

访问路径:http://localhost:8000/app/index/

python 复制代码
before request===== <WSGIRequest: GET '/app/index/'>
before view=======
IndexView======================
raise exception=======
after response======= <HttpResponse status_code=200, "text/html; charset=utf-8">
[16/Jun/2024 19:58:22] "GET /app/index/ HTTP/1.1" 200 16

d. 提供一个测试中间件效果的模板视图

d.提供一个测试中间件效果的模板视图:

python 复制代码
# views.py
from django.template.response import TemplateResponse
from rest_framework.views import APIView

# Create your views here.

class IndexView(APIView):
    def get(self, request):
        print("IndexView======================")
        return TemplateResponse(request, 'index.html')

注意: 只有返回的对象是TemplateResponse 对象或等价方法时,才执行中间件的 process_template_response方法,直接调用render方法无效。
中间件执行结果展示:

访问路径:http://localhost:8000/app/index/

python 复制代码
before request===== <WSGIRequest: GET '/app/index/'>
before view=======
IndexView======================
render template=======
after response======= <TemplateResponse status_code=200, "text/html; charset=utf-8">
[16/Jun/2024 19:59:20] "GET /app/index/ HTTP/1.1" 200 182

TemplateResponse VS render

  • TemplateResponse将模板的渲染延迟到视图完成之后。这允许任何模板响应中间件在响应上运行,并有可能在呈现模板之前更改模板或上下文数据。模板响应中间件运行后,将渲染模板,并在将响应返回给客户端之前对渲染的内容运行常规响应中间件。
  • render立即呈现模板,并返回HttpResponse

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试