中間件------------------------>>>>>>>>>>>>> 中間件是一個用來處理django的響應與請求的框架級別的鉤子.它是一個輕量,低級別的插件系統, 用於在全局範圍內改變django的輸入和輸出,每一箇中間件組件都負責作一些特定的功能. ----簡單來講,Django的中間件是一個類。用來在全局範圍內處理請求和響應。 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. process_request 1. 執行時間 在視圖函數以前執行 2. 參數 request 和視圖中的request是同一個 3. 返回值 返回None 返回response對象 不執行後面中間的process_request方法和視圖 直接執行當前值中間件的process_response方法 4. 執行順序 按照註冊的順序執行 2. process_response 1. 執行時間 在視圖函數以後執行 2. request, response request 和視圖中的request是同一個 response 返回的response對象 3. 返回值 返回response對象 4. 執行順序 按照註冊的倒序執行 3. 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. 執行順序 按照註冊的倒序執行 5. process_template_response(條件觸發:視圖返回的response有render方法) 1. 執行時間 在視圖函數以後,process_response以前執行 2. 參數 3. 返回值 返回 response對象 4. 執行順序 按照註冊的倒序執行,執行完全部的process_template_response方法後執行response.render方法
上一部分,咱們瞭解了中間件中的5個方法,它們的參數、返回值以及何時執行,如今總結一下中間件的執行流程。html
請求到達中間件以後,先按照正序執行每一個註冊中間件的process_reques方法,process_request方法返回的值是None,就依次執行,若是返回的值是HttpResponse對象,再也不執行後面的process_request方法,而是執行當前對應中間件的process_response方法,將HttpResponse對象返回給瀏覽器。也就是說:若是MIDDLEWARE中註冊了6箇中間件,執行過程當中,第3箇中間件返回了一個HttpResponse對象,那麼第4,5,6中間件的process_request和process_response方法都不執行,順序執行3,2,1中間件的process_response方法。python
process_request方法都執行完後,匹配路由,找到要執行的視圖函數,先不執行視圖函數,先執行中間件中的process_view方法,process_view方法返回None,繼續按順序執行,全部process_view方法執行完後執行視圖函數。假如中間件3 的process_view方法返回了HttpResponse對象,則4,5,6的process_view以及視圖函數都不執行,直接從最後一箇中間件,也就是中間件6的process_response方法開始倒序執行。mysql
process_template_response和process_exception兩個方法的觸發是有條件的,執行順序也是倒序。總結全部的執行流程以下:web
小練習:sql
(1)django
AuthMD中間件註冊後,全部的請求都要走AuthMD的process_request方法。瀏覽器
若是URL在黑名單中,則返回This is an illegal URL的字符串;session
訪問的URL在白名單內或者session中有user用戶名,則不作阻攔走正常流程;app
正常的URL可是須要登陸後訪問,讓瀏覽器跳轉到登陸頁面。框架
注:AuthMD中間件中須要session,因此AuthMD註冊的位置要在session中間的下方。
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), url(r'^home/',views.home), url(r'^index/',views.index), url(r'^logout/',views.logout), ]
from django.shortcuts import render,HttpResponse,redirect from django.conf import global_settings # Create your views here. def login(request): err_msg = "" if request.method == "POST": name = request.POST.get("name") pwd = request.POST.get("pwd") if name == "alex" and pwd == "123": request.session['user'] = "user" # request.session.set_expiry(0) #設置關閉瀏覽器後自動註銷 return_path = request.GET.get("return","") if return_path: return redirect(return_path) else: return redirect("/home/") else: err_msg = "用戶名或者密碼錯誤" return render(request,"login.html",{"err_msg":err_msg}) # 登錄裝飾器 # def wrap(func): # def inner(request,*args,**kwargs): # if request.session.get("is_login","") == "True": # ret = func(request,*args,**kwargs) # return ret # else: # path = request.path_info # return redirect("/login/?return={}".format(path)) # return inner # @wrap def home(request): return render(request,"home.html") # @wrap def index(request): return render(request,"index.html") def logout(request): del request.session['user'] return redirect("/login/")
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse, redirect, render class Login_middle(MiddlewareMixin): white_list = ["/login/", ] black_list = ["/black/", ] def process_request(self, request): path = request.path_info if path in self.black_list: return HttpResponse("這是黑名單的網址") elif path in self.white_list or request.session.get("user"): print(11) return else: print(22) return redirect("/login/?return={}".format(path))
'app01.my_middlewaremixin.Login_middle'
#login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> {% csrf_token %} <p>用戶名:<input type="text" name="name"></p> <p>密碼:<input type="password" name="pwd"></p> <p><button>提交</button></p><span>{{ err_msg }}</span> </form> </body> </html> #index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>歡迎登錄index頁面</h1> </body> </html> #home.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>歡迎登錄home頁面</h1> <a href="/logout/">註銷</a> </body> </html>
(2) 限制訪問頻率,一分鐘只能訪問3次.
思路:根據IP作判斷,1分鐘只能訪問3次
1. 獲取ip
2. 記錄時間
3. 根據訪問記錄作判斷
import time l = {} class Throttle(MiddlewareMixin): def process_request(self, request): ip = request.META.get("REMOTE_ADDR") now = time.time() if not l.get(ip, ""): l[ip] = [] history = l[ip] x = [] for i in history: if now - i < 5: x.append(i) print(x) history = x print(history) if len(history) >= 3: return HttpResponse("次數太多了") history.insert(0, now) l[ip] = history
request.META 能夠獲取到全部內容,能夠從中找你想用的東西.一組組鍵值對兒
# {'ALLUSERSPROFILE': 'C:\\ProgramData', # 'APPDATA': 'C:\\Users\\zhanghutao\\AppData\\Roaming', # 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', # 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', # 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', # 'COMPUTERNAME': 'DESKTOP-30PDHUE', # 'COMSPEC': 'C:\\WINDOWS\\system32\\cmd.exe', # 'DJANGO_SETTINGS_MODULE': '中間件.settings', # 'HOMEDRIVE': 'C:', 'HOMEPATH': '\\Users\\zhanghutao', # 'LOCALAPPDATA': 'C:\\Users\\zhanghutao\\AppData\\Local', # 'LOGONSERVER': '\\\\DESKTOP-30PDHUE', # 'MOZ_PLUGIN_PATH': 'E:\\Foxit Reader\\plugins\\', # 'NUMBER_OF_PROCESSORS': '4', # 'ONEDRIVE': 'C:\\Users\\zhanghutao\\OneDrive', # 'OS': 'Windows_NT', # 'PATH': 'C:\\WINDOWS\\system32;' # 'C:\\WINDOWS;' # 'C:\\WINDOWS\\System32\\Wbem;' # 'C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;' # 'C:\\Program Files\\WIDCOMM\\Bluetooth Software\\;C:\\Program Files\\WIDCOMM\\Bluetooth Software\\syswow64;D:\\mysql\\mysql-5.7.23-winx64\\bin;;D:\\PPB\\PBB Reader\\x64;D:\\python3.6\\Scripts\\;D:\\python3.6\\;C:\\Users\\zhanghutao\\AppData\\Local\\Microsoft\\WindowsApps;;D:\\python3.6\\lib\\site-packages\\pywin32_system32;D:\\python3.6\\lib\\site-packages\\pywin32_system32', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 58 Stepping 9, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '3a09', 'PROGRAMDATA': 'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'PROGRAMW6432': 'C:\\Program Files', 'PSMODULEPATH': 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules;C:\\Program Files\\Intel\\Wired Networking\\', 'PUBLIC': 'C:\\Users\\Public', 'PYCHARM_HOSTED': '1', 'PYCHARM_MATPLOTLIB_PORT': '54693', 'PYTHONIOENCODING': 'UTF-8', 'PYTHONPATH': 'D:\\pycharm\\PyCharm 2018.1.3\\helpers\\pycharm_matplotlib_backend;D:\\PythonTest\\django項目\\中間件', 'PYTHONUNBUFFERED': '1', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\WINDOWS', 'TEMP': 'C:\\Users\\ZHANGH~1\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\ZHANGH~1\\AppData\\Local\\Temp', 'USERDOMAIN': 'DESKTOP-30PDHUE', 'USERDOMAIN_ROAMINGPROFILE': 'DESKTOP-30PDHUE', 'USERNAME': 'zhanghutao', 'USERPROFILE': 'C:\\Users\\zhanghutao', 'WINDIR': 'C:\\WINDOWS', 'RUN_MAIN': 'true', 'SERVER_NAME': 'DESKTOP-30PDHUE', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/index/', 'QUERY_STRING': '', # 'REMOTE_ADDR': '127.0.0.1', # 'CONTENT_TYPE': 'text/plain', # 'HTTP_HOST': '127.0.0.1:8000', # 'HTTP_CONNECTION': 'keep-alive', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=HSERiDbpYwWLfLhrjDIgcsMP8HjD1CqXuSPjgSD40l8YpqbMPTYaNKl3xm6MLWne; sessionid=qfrad5a76h2ozt0erj74wef1nrzsl63n', 'wsgi.input': <_io.BufferedReader name=964>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>, 'CSRF_COOKIE': 'HSERiDbpYwWLfLhrjDIgcsMP8HjD1CqXuSPjgSD40l8YpqbMPTYaNKl3xm6MLWne'}