1. Django生命週期
django的生命週期是:前端請求—>nginx—>uwsgi.—>中間件—>url路由---->view視圖—>orm---->拿到數據返回給view---->視圖將數據渲染到模版中拿到字符串---->中間件—>uwsgi---->nginx---->前端渲染。
2. Django中間件
Django 中間件是修改 Django request 或者 response 對象的鈎子,可以理解為是介於 HttpRequest 與 HttpResponse 處理之間的一道處理過程。
瀏覽器從請求到響應的過程中,Django 需要通過很多中間件來處理,可以看如下圖所示:
2.1 內置中間件
- django.middleware.security.SecurityMiddleware
做了一些安全處理的中間件。比如設置防禦的請求頭,比如做了http協議轉為https協議的工作等。
- django.contrib.sessions.middleware.SessionMiddleware
session中間件。會給request添加一個處理好的session對象。
- django.middleware.common.CommonMiddleware
通用中間件,會處理一些URL,比如baidu.com會自動的處理成www.baidu.com。比如/blog/111會處理成/blog/111/自動加上反斜槓。
- django.middleware.csrf.CsrfViewMiddleware
保護中間件,在提交表單的時候會必須加入csrf_token,cookie中也會生成一個名叫csrftoken的值,也會在header中加入一個HTTP_X_CSRFTOKEN的值來放置CSRF攻擊。SessionMiddleware必須出現在CsrfMiddleware之前。
- django.contrib.auth.middleware.AuthenticationMiddleware
用户授權中間件。會給request添加一個user對象的中間件。該中間件必須在sessionmiddleware後面。
- django.contrib.messages.middleware.MessageMiddleware
消息處理中間件。為了在多個模板中可以使用我們返回給模板的變量,並且簡化操作。
- django.middleware.clickjacking.XFrameOptionsMiddleware
防止通過瀏覽器頁面跨Frame出現clickjacking(欺騙點擊)攻擊出現。
中間件組件配置在 settings.py 文件的 MIDDLEWARE 選項列表中,配置中的每個字符串選項都是一個類,也就是一箇中間件。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",
]
2.2 自定義中間件
中間件可以定義五個方法,分別是:
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)
常用的是process_request和process_response,在自己定義中間件時,必須繼承MiddlewareMixin,自定義中間件步驟如下:
①在應用(app1)下創建myMiddleWare.py文件,定義中間件類;
#文件名:myMiddleWare.py
from django.utils.deprecation import MiddlewareMixin
class thCheck(MiddlewareMixin):
def process_request(self, request):
print(8848)
def process_response(self, request, response):
print(9999)
return response
②註冊自定義中間件;
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",
"app1.myMiddleWare.thCheck", # 自定義的中間件
]
③在app1.views.py中定義視圖函數index:
#文件名:app1.views.py
from django.shortcuts import render
from django.http import HttpResponse
from app1.models import Test
# Create your views here.
# 用作測試的視圖函數
def index(request):
print("執行index視圖函數...")
return HttpResponse("index")
def function1(request):
t = Test(name="func1", age=8)
t.save()
return HttpResponse("function1")
def function2(request):
t = Test(name="func2", age=4)
t.save()
return HttpResponse("function2")
④測試:在瀏覽器中訪問http://127.0.0.1:8000/api/app1/index,終端打印如下信息:
3. 典型應用案例
①限制訪問頻率(每分鐘最多訪問10次)
②驗證是否登錄(未登錄用户轉到login界面)
3.1 定義中間件
為了實現限制訪問頻率和驗證登錄兩個功能,分別定義中間件AccessFrequencyMiddleware和LoginRequireMiddleware:
文件名:app1.myMiddleWare.py
import time
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse
class User(object):
def __init__(self, ip):
self.ip = ip
self.reset()
def reset(self):
self.first_time = time.time()
self.counter = 1
# {ip:User()}
user_dict = {}
class AccessFrequencyMiddleware(MiddlewareMixin):
def process_request(self, request):
remote_ip = request.META.get('REMOTE_ADDR')
if remote_ip not in user_dict:
# 用户首次訪問
user_dict[remote_ip] = User(remote_ip)
else:
user = user_dict.get(remote_ip)
time_interval = time.time() - user.first_time
user.counter += 1
if time_interval < 60 and user.counter > 10:
user.last_time = time.time()
user.is_forbidden = True
return HttpResponse('訪問頻率過高,限制訪問')
elif time_interval > 60:
user.reset()
else:
pass
class LoginRequireMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
super().__init__(get_response)
self.get_response = get_response
self.white_list = ["/login/", "/register/"] # 白名單
self.black_list = [] # 黑名單
def process_request(self, request):
path = request.path
print(path, request.user.is_authenticated)
if request.user.is_authenticated or path in self.white_list:
return None
elif path in self.black_list:
return JsonResponse({"code": 0, "error": "禁止訪問"}, status=403)
else:
# viewname 可以是在path()中定義的路由別名name,通過reverse(viewname)函數可以反向查找URL
return HttpResponseRedirect(reverse('login-view'))
3.2 註冊自定義中間件
文件名:django_study.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",
"app1.myMiddleWare.AccessFrequencyMiddleware",
"app1.myMiddleWare.LoginRequireMiddleware",
]
3.3 定義登錄視圖函數
在django_study工程路徑下添加views.py程序,編寫登錄視圖函數:
文件名:django_study.views.py
from django.http import HttpResponse
def login(request):
print("請登錄...")
return HttpResponse("登錄界面")
3.3 註冊視圖函數對應的URL
文件名:django_study.urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
import app1.urls as app1_urls
import app2.urls as app2_urls
from .views import *
urlpatterns = [
path("admin/", admin.site.urls),
path("login/", login, name="login-view"), #視圖函數URL
path("api/app1/", include(app1_urls)),
path("api/app2/", include(app2_urls)),
]
3.4 測試
略