Django框架-中間件

中間件

一、什麼是Django的中間件?

定義:中間件是一個用來處理Django的請求和響應的框架級別的鉤子,它是一個輕量、低級別的插件html

系統,用於在全局範圍內改變Django的輸入和輸出,每一箇中間件組件都負責一些特定的功能。數據庫

白話:中間件就是在視圖函數執行先後作一些額外的操做,本質就是一個自定義的,類中定義幾個方法,用來在全局範圍內處理請求和響應,在特定的時間去執行這些方法。django

介於request與response處理之間的一道處理過程瀏覽器

Django的中間件執行順序按settings.py中MIDDLEWARE註冊索引從小到大執行
服務器

二、Django的默認的中間件

------settings.py
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', ]

主要實現:cookie

用戶登陸session

日誌記錄app

crsf:對全部的post請求作了一個驗證,生成crst_token放在cookie中框架

sessionide

權限管理

注意:對於全部請求的批量作處理的時候用中間件,單獨對某幾個函數作處理的時候用裝飾器

三、定義5個方法

process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)

四、方法的執行時間及執行順序

4.一、process_request

1. 執行時間
    在視圖函數以前執行
2. 參數
    request 和視圖中的request是同一個
3. 返回值
    返回None
    返回response對象
        不執行後面中間的process_request方法和視圖
        直接執行當前值中間件的process_response方法
4. 執行順序
    按照註冊的順序執行

4.二、process_response

1. 執行時間
    在視圖函數以後執行
2. request, response
    request 和視圖中的request是同一個
    response 返回的response對象
3. 返回值
    返回response對象
4. 執行順序
    按照註冊的倒序執行

4.三、process_view

1. 執行時間
    在視圖函數以前,process_request以後執行
2. 參數
    view_func  將要執行的視圖函數
    view_args  視圖函數的可變長位置參數
    view_kwargs 視圖函數的可變長關鍵字參數
3. 返回值
    返回  None  正常執行
    返回  response對象   不執行後面的process_view和視圖,直接執行全部中間件的process_response方法

4.執行順序
    按照註冊的順序執行

4.四、process_exception(有條件觸發:有錯誤才執行)

1. 執行時間
    在視圖函數以後,process_response以前執行
2. 參數
    exception  錯誤對象
3. 返回值
    返回  None  不對錯誤進行處理,交給下一個中間件進行處理
    返回  response對象  下一個中間的process_exception不執行,直接執行全部中間件的process_response方法
4. 執行順序
    按照註冊的倒序執行

4.五、process_template_response(條件觸發:視圖返回的response有render方法)

1. 執行時間
    在視圖函數以後,process_response以前執行
2. 參數
3. 返回值
    返回 response對象
4. 執行順序
    按照註冊的倒序執行,執行完全部的process_template_response方法後執行response.render方法

六、中間件執行流程圖

七、django請求的生命週期圖

八、自定義中間件步驟

8.一、在應用app的根目錄下建立一個文件夾midd_test,文件夾裏建立一個py文件eg:midd.py
8.二、在midd.py中導入模塊:from django.utils.deprecation import MiddlewareMixin
8.三、在midd.py中寫類且必須繼承MiddlewareMixin類,類裏寫幾個方法
8.四、在項目setting.py中的MIDDLEWARE模塊加上自定義的中間件路勁,
格式爲:app_name.文件夾.py文件名.類名 eg: 'middlewares_app.midd_test.midd.Throttle',

九、中間件的方式解決登陸

中間件版的登陸驗證須要依靠session,因此數據庫種要有django_session表。

urlls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/$, views.login , name='login'),
    url(r'^index/$', views.index, name='index'),
    url(r'^home/$', views.home, name='home'),    
]
View Code

views.py

 1 from django.shortcuts import render, HttpResponse, redirect
 2 from app01 import models
 3 
 4 
 5 def index(request):
 6     return HttpResponse('this is index page')
 7 
 8 
 9 def home(request):
10     return HttpResponse('this is home page')
11 
12 
13 def login(request):
14     if request.method == 'POST':
15         user = request.POST.get('user', '')
16         pwd = request.POST.get('pwd', '')
17         check = models.UserInfo.object.filter(username=user, password=pwd)
18         if check:
19             # 設置session
20             request.session['user'] = user
21             # 獲取跳轉登陸頁面以前的url
22             next_url = request.GET.get('next')
23             # 若是有,就跳轉回登錄以前的url,不然默認跳轉到index頁面
24             if next_url:
25                 return redirect(to=next_url)
26             else:
27                 # return redirect('/index/')
28                 from django.shortcuts import reverse
29                 return redirect(reverse(viewname=index))  # url反向解析
30     return render(request, 'login.html')
View Code

login.html

 1 {% load static %}
 2 <!DOCTYPE html>
 3 <html lang="en">
 4 <head>
 5     <meta charset="UTF-8">
 6 {#<link rel="icon" href="/static/Bootstrap/imags/logo.jpg"> 下面的方式是靜態文件動態#}
 7     <link rel="icon" href="{% static 'Bootstrap/imags/logo.jpg' %}">
 8     <title>登錄頁面</title>
 9 </head>
10 <body>
11 <form action="{% url 'login' %}">
12     {% csrf_token %}
13     <div>
14         <label for="user">用戶名:</label>
15         <input type="text" id="user" name="user">
16     </div>
17     <div>
18         <label for="pwd">用戶名:</label>
19         <input type="password" id="pwd" name="pwd">
20     </div>
21     <p><input type="submit" value="登陸"></p>
22 </form>
23 </body>
24 </html>
View Code

mymidd.py

 1 from django.utils.deprecation import MiddlewareMixin
 2 
 3 
 4 class AuthMd(MiddlewareMixin):
 5     white_list = ['/login/', ]   # 白名單
 6     black_list = ['/black/', ]   # 黑名單
 7 
 8     def  process_request(self,request):
 9         from django.shortcuts import redirect, HttpResponse
10         
11 
12  next_url = request.path_info 13         # 黑名單的網址限制訪問
14         if  next_url  in  self.black_list:
15             return   HttpResponse('this is an illegal url')
16         elif  next_url in self.white_list or request.session.get('user'): 17             return None
18         else:
19             return redirect('/login/?next={}'.format(next_url))

settings.py中註冊自定義的中間件

 1 MIDDLEWARE = [
 2     'django.middleware.security.SecurityMiddleware',
 3     'django.contrib.sessions.middleware.SessionMiddleware',
 4     'django.middleware.common.CommonMiddleware',
 5     'django.middleware.csrf.CsrfViewMiddleware',
 6     'django.contrib.auth.middleware.AuthenticationMiddleware',
 7     'django.contrib.messages.middleware.MessageMiddleware',
 8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 9     'mymiddl.AuthMd'
10 ]
11 
12 註冊中間件
View Code

AuthMd中間件註冊後,全部的請求都要走AuthMd的process_request方法。

若是url在黑名單中,則返回this is an illegal url;

訪問的url在白名單內或者session中有urser用戶名,則不作阻攔走正常流程,不須要登陸就能夠訪問,如正常的註冊,登陸,主頁;

其它正常的url都是須要登陸後訪問,讓瀏覽器跳轉到登陸頁面。

注:AuthMd中間件須要session,因此AuthMd註冊的位置須要在session中間的下方。

十、中間件的方式作分流控制

 1 # 存放用戶數據
 2 visit_list = {
 3     # ip:[]  訪問ip對應,每次訪問時間
 4 
 5 
 6 
 7 class Throttle(MiddlewareMixin):
 8     """獲取ip,記錄時間,記錄次數,根據訪問記錄作判斷"""
 9 
10     def process_request(self, request):
11         print(request.META)
12         ip = request.META.get('REMOTE_ADDR')  # 獲取訪問ip
13         now = time.time()  # 記錄當前時間,每次時間加入到最前面,即列表索引爲0的位置
14         if not visit_list.get(ip, ''):  # 首先判斷當前訪問ip是否在列表中
15             visit_list[ip] = []  # 不在的話,將訪問ip加入到字典中,並建立value爲空列表
16         # visit_list[ip].insert(0, now)
17         # 在的話,比較訪問時間是否在10秒內,就能夠訪問,故刪除以前的時間,將當前的時間寫入
18         # 若是ip存在獲取ip的訪問時間記錄列表
19         history = visit_list[ip]
20         print(history)
21         temp_list = []  # 解決循環刪除列表問題
22         for i in history:
23             if now - i > 10:  # 若是相距上次訪問大於10秒,就將以前的清除[以防因記錄3次致使符合要求的沒法訪問],將本次的時間寫入
24                 temp_list.append(i)  # 加入到臨時列表
25             else:
26                 # 再若是ip存在且在10秒內再次訪問,檢查訪問的次數
27                 if len(history) >= 3:  # 就不須要再加入時間了,直接返回警告
28                     return HttpResponse('訪問頻率太快了,請等10秒後再來訪問')
29         for j in temp_list:
30             history.remove(j)
31         history.insert(0, now)
32 
33 
34 ------------------------------------------------------------------------------------
35 class Throttle(MiddlewareMixin):
36     """獲取ip,記錄時間,記錄次數,根據訪問記錄作判斷"""
37 
38     def process_request(self, request):
39         ip = request.META.get('REMOTE_ADDR')
40         now = time.time()
41         if not visit_list.get(ip, ""):
42             visit_list[ip] = []  # 添加新用戶,建立key:vulue
43             visit_list[ip].insert(0, now)  # 每次都添加到第一個位置
44         else:
45             if now - visit_list[ip][0] > 10:  # 超過10秒更新最新訪問時間
46                 visit_list[ip].clear()   # 清空列表
47                 visit_list[ip].insert(0, now)
48             else:  # 未超過10秒,再來檢測已訪問的次數
49                 if len(visit_list[ip]) >= 3:
50                     return HttpResponse('too fast ,waiting a moment')
51                 else:
52                     visit_list[ip].insert(0, now)   # 小於三次就把時間記錄上
53 
54 --------------------------------------------------------------------------------------
55 visit_list = {
56     # 127.0.0.1:[]
57 }
58 
59 class Throttle(MiddlewareMixin):
60 
61     def process_request(self, request):
62         # 1.
63         # 獲取ip
64         ip = request.META.get('REMOTE_ADDR')
65 
66         if not visit_list.get(ip, ''):
67             visit_list[ip] = []
68         history = visit_list[ip]
69         now = time.time()
70         # [ 10:21:10 ,10:21:06 ,10:21:05 ]
71         # 2. 記錄時間
72         # 3. 根據訪問記錄作判斷
73         while history and now - history[-1]>5:
74             history.pop()
75 
76         if len(history) >= 3:
77             return HttpResponse('頻率太快了')
78         history.insert(0,now)
未優化版
 1 -----midd.py    # 在本身建立的py文件中寫以下類
 2 
 3 import time
 4 from django.utils.deprecation import MiddlewareMixin
 5 from django.shortcuts import HttpResponse
 6 
 7 """
 8 # 需求:限制訪問頻率&限制用戶10秒內訪問同一頁面最多3次,防止重複請求,增長服務器壓力
 9 思路:
10 一、獲取訪問用戶的ip
11 二、記錄每次用戶訪問該頁面時的時間
12 三、比較用戶每次訪問時與前一次訪問時間,若是超過10秒,能夠繼續訪問,記錄時間,
13 若是未超過,再看是否超過3次,若是超過次數,拒絕訪問
14 四、設計存放用戶訪問記錄的格式:{ip:[time1,time2,time3]}
15 五、每次過來經過ip獲取上次的訪問時間,作比較
16 """
17 
18 # 存放用戶數據
19 visit_list = {
20     # ip:[]  訪問ip對應,每次訪問時間
21 }
22 
23 class Throttle(MiddlewareMixin):
24     """獲取ip,記錄時間,記錄次數,根據訪問記錄作判斷"""
25 
26    def process_request(self, request):
27         ip = request.META.get('REMOTE_ADDR')
28         now = time.time()
29         if not visit_list.get(ip, ""):
30             visit_list[ip] = []  # 添加新用戶,建立key:vulue
31         else:
32             if now - visit_list[ip][0] > 10:  # 超過10秒更新最新訪問時間
33                 visit_list[ip].clear()  # 清空列表
34             else:  # 未超過10秒,再來檢測已訪問的次數
35                 if len(visit_list[ip]) >= 3:
36                     return HttpResponse('too fast ,waiting a moment')
37         visit_list[ip].insert(0, now)  # 小於三次就把時間記錄上 , 每次都添加到第一個位置上面的邏輯是錯的,好比用戶1,2,3秒時訪問,屬於10秒內3次訪問,經過,第4秒時,小於10秒,但表中已經有3個了,不能訪問,ok,但用戶第11秒時訪問,這時過來10秒,應該能訪問,但雖然與最後一次時間比小於10秒,但列表中已經有了3個時間,就致使不能訪問了,因此邏輯是錯的,須要將最開始訪問和如今時間比超過10秒的刪除掉,保證列表中的時間永遠是10秒內的。
相關文章
相關標籤/搜索