乐趣区

关于python: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 笔记。

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

如果想获取更多相干文章,可扫码关注浏览:

退出移动版