定義:中間件是一個用來處理Django的請求和響應的框架級別的鉤子,它是一個輕量、低級別的插件html
系統,用於在全局範圍內改變Django的輸入和輸出,每一箇中間件組件都負責一些特定的功能。數據庫
白話:中間件就是在視圖函數執行先後作一些額外的操做,本質就是一個自定義的類,類中定義幾個方法,用來在全局範圍內處理請求和響應,在特定的時間去執行這些方法。django
介於request與response處理之間的一道處理過程瀏覽器
Django的中間件執行順序按settings.py中MIDDLEWARE註冊索引從小到大執行
服務器
------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
權限管理
注意:對於全部請求的批量作處理的時候用中間件,單獨對某幾個函數作處理的時候用裝飾器
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)
1. 執行時間
在視圖函數以前執行
2. 參數
request 和視圖中的request是同一個
3. 返回值
返回None
返回response對象
不執行後面中間的process_request方法和視圖
直接執行當前值中間件的process_response方法
4. 執行順序
按照註冊的順序執行
1. 執行時間
在視圖函數以後執行
2. request, response
request 和視圖中的request是同一個
response 返回的response對象
3. 返回值
返回response對象
4. 執行順序
按照註冊的倒序執行
1. 執行時間
在視圖函數以前,process_request以後執行
2. 參數
view_func 將要執行的視圖函數
view_args 視圖函數的可變長位置參數
view_kwargs 視圖函數的可變長關鍵字參數
3. 返回值
返回 None 正常執行
返回 response對象 不執行後面的process_view和視圖,直接執行全部中間件的process_response方法
4.執行順序
按照註冊的順序執行
1. 執行時間
在視圖函數以後,process_response以前執行
2. 參數
exception 錯誤對象
3. 返回值
返回 None 不對錯誤進行處理,交給下一個中間件進行處理
返回 response對象 下一個中間的process_exception不執行,直接執行全部中間件的process_response方法
4. 執行順序
按照註冊的倒序執行
1. 執行時間
在視圖函數以後,process_response以前執行
2. 參數
3. 返回值
返回 response對象
4. 執行順序
按照註冊的倒序執行,執行完全部的process_template_response方法後執行response.render方法
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'), ]
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')
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>
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 註冊中間件
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秒內的。