中间件

2. 自定义中间件

上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin

需要导入

from django.utils.deprecation import MiddlewareMixin

一、process_request,process_response

process_response方法必须返回response!
url等略,下面只展示关键代码

views.py:

from django.shortcuts import render,HttpResponse,redirect
def index(request):
    print("view函数...")
    return HttpResponse("OK")

应用/my_middlewares.py

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

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
    def process_response(self,request,response):
        print("Md2返回")
        return response

执行结果

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

注意:如果当请求到达请求1的时候直接不符合条件返回,即return HttpResponse("Md1中断"),程序(跳过process_view,url,视图函数,process_exception)将把请求直接发给中间件1返回,,然后依次返回到请求者,结果如下:

Md1请求
Md1返回

流程图如下:

二、process_view

process_view使用如下

process_view(self, request, callback, callback_args, callback_kwargs)
callback 是当前请求的视图函数,callback_args, callback_kwargs是请求的参数,这一步在视图层之前执行

my_middlewares.py修改如下

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

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md1view")

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md2view")

结果如下:

Md1请求
Md2请求
Md1view
Md2view
view函数...
Md2返回
Md1返回

流程如下:

process_view可以用来调用视图函数:

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        # Md1 view 中断
        # return HttpResponse("hello")

        response=callback(request,*callback_args,**callback_kwargs)
        return response

执行结果:

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

注意:process_view如果有返回值HttpResponse类的相应函数,会越过其他的process_view以及视图函数,直接依次执行所有的process_response。

三、process_exception

process_exception是当视图函数抛出错误后执行的(视图函数没有解决错误)!

使用方法:

process_exception(self, request, exception)

自定义示例修改如下:

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        # response=callback(request,*callback_args,**callback_kwargs)
        # return response
        print("md1 process_view...")

    def process_exception(self):
        print("md1 process_exception...")



class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        # return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("md2 process_view...")

    def process_exception(self):
        print("md1 process_exception...")

结果:

Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...

Md2返回
Md1返回

当views出现错误时:
将md2的process_exception修改如下:

def process_exception(self,request,exception):

        print("md2 process_exception...")
        return HttpResponse("error")

结果如下

Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
md2 process_exception...
Md2返回
Md1返回

注意:同process_view,如果process_exception有返回值HttpResponse类的相应函数,会越过其他的process_exception,直接依次执行所有的process_response。


3. 案例展示

  1. 通过中间件实现用户认证--session查询
  2. 限制每10秒访问不超过4次!

项目文件/setting.py

MIDDLEWARE = [
    ...其定义的中间件
    'app01.my_middlewares.AuthMiddleware',
]
# 配置不需要登录验证的白名单
WHITE_LIST = ['/login/', '/reg/', '/logout/']

项目文件/urls.py

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('index/', views.index),
]

应用文件夹/models.py

from django.db import models
class IpInfo(models.Model):
    id = models.AutoField(primary_key=True)
    addr = models.CharField(max_length=15)
    timestamp = models.FloatField()
    accessTime = models.IntegerField(default=0)

应用文件夹/自定义中间件my_middlewares.py

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,redirect,render

# 从配置文件引入不需要认证的自定义白名单
from AjaxDemo.settings import WHITE_LIST
from django.db.models import F
from app01.models import IpInfo
import time

class AuthMiddleware(MiddlewareMixin):
    def process_request(self, request):
        """获取客户端的IP
        有些网站服务器会使用ngix等代理http,或者是该网站做了负载均衡,
        导致使用remote_addr抓取到的是1270.0.1,这时使用HTTP_X_FORWARDED_FOR
        才获得是用户的真实IP。推荐使用以下代码:
        """
        if request.META.get('HTTP_X_FORWARDED_FOR', None):
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:
            ip = request.META['REMOTE_ADDR']
        # 限制用户10秒内只能
        now = time.mktime(time.gmtime())

        clientQ = IpInfo.objects.filter(addr=ip)
        client = clientQ.first()

        if not client:
            IpInfo.objects.create(addr=ip, timestamp=now, accessTime=1)
        else:
            last_access_time = client.timestamp
            accessTimes = client.accessTime
            print("持续时间:", now - last_access_time)
            if now - last_access_time < 10:
                if accessTimes > 3:
                    return HttpResponse("本次访问被限制,请耐心等待!或者,你是一个机器人儿也说不定!")
                else:
                    clientQ.update(accessTime=F('accessTime') + 1)
            else:
                clientQ.update(addr=ip, timestamp=now, accessTime=1)


        if request.path in WHITE_LIST:
            return None # 不执行操作

        # 重定向到登录页面
        if not request.user.is_authenticated:
            return redirect('/login/')

应用文件夹/views.py

def index(reqest):
    print("in views.........")
    return HttpResponse("in views")
posted @ 2018-08-17 00:00  哈哈大圣  阅读(72)  评论(0编辑  收藏  举报