本文首发于公众号:Hunter后端

原文链接:Django笔记二十九之中间件介绍

这一节介绍一下 Django 的中间件。

关于中间件,官方文档的解释为:中间件是一个嵌入 Django 系统的 request 和 response 的钩子框架,是一个能够全局改变 Django 输入/输出的系统。

我们可以这样理解,一个 request 请求发送到 Django 系统的过程中,在经过路由和视图的处理前,会先经过一层处理,这个处理操作可以是日志记录,可以是登录验证甚至你想在系统里定义的功能,这个操作就是中间件实现的功能。

接下来我们将通过一个记录请求的 ip 的功能的介绍来介绍一下中间件的实现流程。

以下是本篇笔记目录:

  1. 请求经过 Django 然后返回的流程
  2. HttpRequest 和 HttpResponse 介绍
  3. 中间件的示例介绍
  4. 记录访问 ip 的功能实现

1、请求经过 Django 然后返回的流程

首先,前端发起一个请求,这个请求经由 web 服务器转发给 Django 系统,在进入 Django 系统后会先经过一系列的中间件的功能处理。

这个中间件会在 settings.py 里定义,Django 系统默认自带的中间件列表如下:

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',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

这些中间件我们也可以根据自己的需求自己定义,比如新加一个登录权限,或者日志记录,或者对输入的参数进行格式化处理也可以,或者自己想要设置的其他功能也行,具体怎么设置在后面介绍。

在中间件处理的流程中,请求会被按照顺序从上往下处理。

这个流程过后,一个 request 请求才会被进行 URL 的路径匹配,如果匹配上,再去找相应的 views 视图函数进行数据处理

views 处理完之后,会形成一个 response,返回,然后再次经历这个中间件处理,因为在每一层中间件中都类似于一种嵌套,所以返回 response 的时候,是从下往上再次处理 response 的。

中间件处理结束之后再被返回出去,给到前端。

在这整个流程处理中,可以说中间件是进行了两次操作,一个是进入的时候处理 request,一个是返回的时候处理 response。

2、HttpRequest 和 HttpResponse 介绍

我们先来看一个视图函数:

def time_view(request):
now = datetime.datetime.now()
html = "<h1>now: %s</h1>abc\nabc" % now
return HttpResponse(html)

当 Django 接收到一个请求,系统会创建一个 HttpRequest 对象,这个对象就是上面的视图函数里的输入参数,request

在对数据进行处理后,系统会返回一个 HttpResponse 对象,这个就是我们 return 的内容。

在一个 HttpRequest 对象里,会包含请求的路径、参数、请求方式、 cookie 等一切请求过来时的数据,我们可以在请求的时候根据需要存取。

在返回的 HttpResponse 中,可以是一个 html 页面,也可以是 json 格式的数据,内容是可以自定义的,只要前端可以做相应的处理。

3、中间件的示例介绍

接下来我们定义一个中间件,结构大致如下:

# huter/middleware.py

class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response def __call__(self, request): # 在请求进入视图函数前的可以执行一些操作,针对 request
print(request.path)
response = self.get_response(request) # 在处理完请求后,可以执行一些操作,针对 response
# log_response_info()
return response

然后我们在 sttings.py 里引入这个中间件,我们放到 MIDDLEWARE 列表的最下面,说明这个中间件会在其他中间件处理完 request 之后再处理:


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',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'hunter.middleware.TestMiddleware',
]

在 SimpleMiddleware 这个类里,call() 函数会自动调用,其中有一行,response = self.get_response(request)

在这一行函数之前,可以对请求的 request 做处理,包括我们前面说的各种功能,比如日志、登录验证、参数格式化等

在这一行函数之后,获取了 response,这个就是视图函数返回的 HttpResponse,我们可以在这里对它的 response.status_code 状态码,和 response.content 做处理

比如前面 time_view 函数返回的内容是一个 JsonResponse:

return JsonResponse({"code": 0})

那么在这里我们可以获取然后处理这个 HttpResponse:


def __call__(self, request): response = self.get_response(request) content = json.loads(response.content)
content["msg"] = "success"
response.content = json.dumps(content)
return response

这里只是一个示例,因为并不是所有的 HttpResponse 都是 json 格式的数据,所以可能需要加一个 try except 做下处理

还有一个功能是我之前做过的,就是在 headers 中加一个特定的字符串,表示是我们系统专有的,用于前端判断,这个很简单,就是在 response 的 headers 参数中加一个键值对:

response.headers['system'] = 'hunter'

以上就是一个最简单的中间件的处理方式。

process_view

除了 call 函数以外,还有一个 process_view() 的函数

这个函数是在 Django 系统调用 views 视图函数前被调用,它的返回值是 None 或者一个 HttpResponse

如果为 None,那么系统会接着调用视图函数,如果是 HttpResponse 作为返回值,说明系统在这里已经处理了请求,不需要再走views视图函数,然后就会直接返回。

我们通过下面的例子来解释这个函数作用。

4、记录访问 ip 的功能实现

假设我们需要禁止某一个或者某一个 ip 列表的请求访问我们的系统

当然,这个操作,在 web 服务器那部分就可以拦截,这里就是单纯举个例子

那么我们这样设置一个 process_view 的功能,在真正执行视图函数(也就是url 匹配上的 view函数)前,取出这个 request 的访问的ip,然后进行判断,如果在 禁止列表,那么则直接返回一个禁止访问的页面。

class TestMiddleware:
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):
EXCLUDE_IPS = ['192.168.1.54']
if 'HTTP_X_FORWARDED_FOR' in request.META:
ip = request.META['HTTP_X_FORWARDED_FOR']
else:
ip = request.META['REMOTE_ADDR']
if ip in EXCLUDE_IPS:
return HttpResponse('<h1>您的ip被禁止</h1>')
return None

在这里,我们拿到请求的 ip 地址,去和我们定义的禁止ip列表做比较

如果在禁用列表,则直接返回 HttpResponse,不接着请求我们的服务来

否则,就返回 None,系统接收到 None 之后,会接着往下处理。

如果想获取更多后端相关文章,可扫码关注阅读:

Django笔记二十九之中间件介绍的更多相关文章

  1. 应用程序框架实战二十九:Util Demo介绍

    上文介绍了我选择EasyUi作为前端框架的原因,并发放了最新Demo.本文将对这个Demo进行一些介绍,以方便你能够顺利运行起来. 这个Demo运行起来以后,是EasyUi的一个简单CRUD操作,数据 ...

  2. angular学习笔记(二十九)-$q服务

    angular中的$q是用来处理异步的(主要当然是http交互啦~). $q采用的是promise式的异步编程.什么是promise异步编程呢? 异步编程最重要的核心就是回调,因为有回调函数,所以才构 ...

  3. 论文阅读笔记二十九:SSD: Single Shot MultiBox Detector(ECCV2016)

    论文源址:https://arxiv.org/abs/1512.02325 tensorflow代码:https://github.com/balancap/SSD-Tensorflow 摘要 SSD ...

  4. Java学习笔记二十九:一个Java面向对象的小练习

    一个Java面向对象的小练习 一:项目需求与解决思路: 学习了这么长时间的面向对象,我们只是对面向对象有了一个简单的认识,我们现在来做一个小练习,这个例子可以使大家更好的掌握面向对象的特性: 1.人类 ...

  5. Java笔记(二十九)……网络编程

    概述 网络模型 网络通讯的要素 ip地址:网络中设备的标识符 端口:用于标识同一台设备上不同的进程,有效端口:0~65535,其中0~1024是系统使用端口或者保留端口 TCP与UDP UDP特点: ...

  6. PHP学习笔记二十九【接口】

    <?php //定义接口 //接口可以定义属性,但必须是常量而且是public //接口的所有方法必须是public interface Iusb{ public function start( ...

  7. Python笔记(二十九)_模块

    模块 在Python中,一个.py文件就是一个模块 if __name__ == '__main__':所有模块都有一个 __name__ 属性,__name__ 的值取决于如何应用模块 run当前文 ...

  8. FreeSql (二十九)Lambda 表达式

    FreeSql 支持功能丰富的表达式函数解析,方便程序员在不了解数据库函数的情况下编写代码.这是 FreeSql 非常特色的功能之一,深入细化函数解析尽量做到满意,所支持的类型基本都可以使用对应的表达 ...

  9. 剑指Offer(二十九):最小的K个数

    剑指Offer(二十九):最小的K个数 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/baid ...

  10. 《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)

    1.简介 有些测试场景或者事件,Selenium根本就没有直接提供方法去操作,而且也不可能把各种测试场景都全面覆盖提供方法去操作.比如:就像鼠标悬停,一般测试场景鼠标悬停分两种常见,一种是鼠标悬停在某 ...

随机推荐

  1. IDEA设置编码为UTF-8编码

    IntelliJ IDEA 统一设置编码为utf-8编码 问题一: File->Settings->Editor->File Encodings 网上的方法大部分都是错的,上图的单选 ...

  2. 狂神的学习笔记demo04

    package com.company; public class demo04 { public static void main(String[] args){ int i=10;//二进制 in ...

  3. Python机器学习/LogisticRegression(逻辑回归模型)(附源码)

    LogisticRegression(逻辑回归) 逻辑回归虽然名称上带回归,但实际上它属于监督学习中的分类算法. 1.算法基础 LogisticRegression基本架构源自于Adline算法,只是 ...

  4. 003Java的诞生

    003Java的诞生 1.计算机语言发展史 (1)第一代语言 机器语言 我们都知道计算机的基本计算方式都是基于二进制的方式. 二进制:010111001010110010110100 这种代码是直接输 ...

  5. gstreamer样例

    #!/bin/bash xrandr -s 0 --output DSI-1 xrandr -s 0 --output HDMI-1 xrandr --fb 1024x600 --output DSI ...

  6. EVE如何提升名望值

    目录 背景介绍 简介 名望值划分 军团名望值 利弊 背景介绍 ​ 玩eve将近3个星期,开着毒蜥级刷1级代理人任务感觉没有一点难度,想尽快刷3.4级代理任务,而我目前能够接到的最高代理任务也就才1级. ...

  7. C语言中~与!的区别

    ! 是逻辑非or否定 ​ 凡是a的值不为0的,!a 就等于0: ​ 如果a的值为0,则 !a 的值为1 而~这个是 按位取反 比如 int a=2 ; 用二进制表示为00 00 00 10; 则 !a ...

  8. 6 Sampling Configuration Space: 6.4 Adaptive Steered Molecular Dynamics

    6.4 Adaptive Steered Molecular Dynamics 理论背景: SMD 利用施加steering力的伪粒子,以便以特定速度穿过反应坐标. 这个外力允许人们在MD模拟时间尺度 ...

  9. vs2022和wsl2开发和调试c++代码(转载)

    看见一个不错的帖子(知乎) https://zhuanlan.zhihu.com/p/390757559 里面最主要就是要保证wsl里面安装的东西够了,第二就是vs2022已经安装了linux的相关模 ...

  10. c++中文编码格式

    c++程序中涉及到中文字符的输入输出以及其他操作经常会出现乱码.乱码主要是由于程序的源文件编码.可执行文件编码以及程序运行环境的编码不匹配导致.比如,c++源程序文件编码为GB18030, 在源程序中 ...