中間件顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,而且在全局上改變django的輸入與輸出。由於改變的是全局,因此須要謹慎實用,用很差會影響到性能。前端
Django的中間件官方的定義:python
Middleware is a framework of hooks into Django’s request/response processing. <br>It’s a light, low-level 「plugin」 system for globally altering Django’s input or output.django
若是你想修改請求,例如被傳送到view中的HttpRequest對象。 或者你想修改view返回的HttpResponse對象,這些均可以經過中間件來實現。後端
可能你還想在view執行以前作一些操做,這種狀況就能夠用 middleware來實現。瀏覽器
說的直白一點中間件是幫助咱們在視圖函數執行以前和執行以後均可以作一些額外的操做,它本質上就是一個自定義類,類中定義了幾個方法,Django框架會在請求的特定的時間去執行這些方法。session
咱們一直都在使用中間件,只是沒有注意到而已,打開Django項目的Settings.py文件,看到下面的MIDDLEWARE配置項。app
Django默認的Middleware:框架
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',
]
MIDDLEWARE配置項是一個列表,列表中是一個個字符串,這些字符串實際上是一個個類,也就是一個個中間件。
注意:
對於全部請求的批量作處理的時候用中間件
單獨對某幾個函數作處理的時候用裝飾器
中間件能夠定義五個方法,分別是:(主要的是process_request和process_response)
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)
以上方法的返回值能夠是None或一個HttpResponse對象,若是是None,則繼續按照django定義的規則向後繼續執行,若是是HttpResponse對象,則直接將該對象返回給用戶。
當用戶發起請求的時候會依次通過全部的的中間件,這個時候的請求時process_request,最後到達views的函數中,views函數處理後,在依次穿過中間件,這個時候是process_response,最後返回給請求者。
(1)先建一個文件夾,裏面寫一個py文件
(2)而後開始寫類
1.中間件就是一個類,類裏面寫幾個方法
class M1(MiddlewareMixin): 必須繼承
def process_request(self,request): request:請求裏面的全部的東西
print("m1.request_request")
#這個方法裏面別輕易返回值,要是有返回值就再也不繼續執行後面的了,
#執行本身的process_response和上邊的response
# 通常是無返回值的:繼續執行後續的中間件和視圖函數
def process_response(self,request,response):
return response
2.在settings中的MIDDLEWARE加上路徑
文件夾名稱.py文件名稱.類名
注意註冊的書寫格式爲:app名.寫自定義中間件的文件名.類名
如例子MIDDLEWARE註冊截圖所示:
相應的項目目錄截圖爲:
3.找到繼承的那個類,把那個類拿過來
通常不要用導入的方法,否則有時候更新了就沒有這個類了,你就把它繼承的那個類拿過來。
process_request有一個參數,就是request,這個request和視圖函數中的request是同樣的。
它的返回值能夠是None也能夠是HttpResponse對象。返回值是None的話,按正常流程繼續走,交給下一個中間件處理,若是是HttpResponse對象,Django將不執行視圖函數,而將響應對象返回給瀏覽器。
咱們來看看多箇中間件時,Django是如何執行其中的process_request方法的。
(1)首先是寫一個視圖函數及相應的路由配置,這邊就不作多講解,前面內容都有相關步驟。
視圖函數內容爲:
def index(request):
print("運行了index視圖函數。。。")
return HttpResponse("ok")
沒有自定義中間件的時候,訪問index能夠返回ok,而且後端打印print的內容。
(2)註冊自動中間件
詳見上面截圖
(3)自定義中間件內容:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class mid1(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,
# 而且會直接返回當前類下的process_response方法.
print("mid1裏面的 process_request")
# return HttpResponse("md1__request方法")
class mid2(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid1裏面的 process_request")
(4)運行訪問沒有返回值的打印狀況
(5)運行訪問有返回值的時候
如上自定義中間件內容將process_request的函數的返回值的註釋去掉,則後端以下打印:
前端打印:
(6)得出中間件運行的過程以下圖箭頭走勢
多箇中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最後執行,最後一箇中間件的process_request方法最後一個執行,它的process_response方法是最早執行。
它有兩個參數,一個是request,一個是response,request就是上述例子中同樣的對象,response是視圖函數返回的HttpResponse對象。該方法的返回值也必須是HttpResponse對象。
給3中的例子中都加上process_response方法以下代碼:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class mid1(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid1裏面的 process_request")
# return HttpResponse("mId1__request方法")
def process_response(self, request, response):
print("mid1裏面的 process_response")
return response
class mid2(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid2裏面的 process_request")
def process_response(self, request, response):
print("mid2裏面的 process_response")
return response
正常運行爲後端打印爲:
若是將process_request中的返回註釋去掉打印爲:
只走了mid1類的process_request和process_response的函數,mid2的不運行,且視圖函數不運行。
可知獲得的流程爲:
process_view(self, request, view_func, view_args, view_kwargs)
該方法有四個參數
request是HttpRequest對象。
view_func是Django即將使用的視圖函數。 (它是實際的函數對象,而不是函數的名稱做爲字符串。)
view_args是將傳遞給視圖的位置參數的列表.
view_kwargs是將傳遞給視圖的關鍵字參數的字典。 view_args和view_kwargs都不包含第一個視圖參數(request)。
Django會在調用視圖函數以前調用process_view方法。
它應該返回None或一個HttpResponse對象。 若是返回None,Django將繼續處理這個請求,執行任何其餘中間件的process_view方法,而後在執行相應的視圖。 若是它返回一個HttpResponse對象,Django不會調用適當的視圖函數。 它將執行中間件的process_response方法並將應用到該HttpResponse並返回結果。
例:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class mid1(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid1裏面的 process_request")
# return HttpResponse("mId1__request方法")
def process_response(self, request, response):
print("mid1裏面的 process_response")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("mid1 中的process_view")
# return view_func(request)
class mid2(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid2裏面的 process_request")
def process_response(self, request, response):
print("mid2裏面的 process_response")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("mid2 中的process_view")
正常運行打印爲:
若是在process_view處的註釋的返回值去掉註釋得:
從正常的分析得出,process_view方法是運行在視圖函數以前的,若是將
return view_func(request) 加到mid1類process_view方法中時,process_view直接調用視圖函數執行,並返回結果,緊接着直接執行process_response的方法,跳過了mid2中的process_view方法。
獲得流程圖爲:
process_exception(self, request, exception)
該方法兩個參數:
HttpRequest對象
exception是視圖函數異常產生的Exception對象。
這個方法只有在視圖函數中出現異常了才執行,它返回的值能夠是一個None也能夠是一個HttpResponse對象。若是是HttpResponse對象,Django將調用模板和中間件中的process_response方法,並返回給瀏覽器,不然將默認處理異常。若是返回一個None,則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件註冊順序的倒序執行。process_exception方法是執行在視圖函數以後的。
例:
中間件內容代碼變爲:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class mid1(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid1裏面的 process_request")
# return HttpResponse("mId1__request方法")
def process_response(self, request, response):
print("mid1裏面的 process_response")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("mid1 中的process_view")
# return view_func(request)
def process_exception(self, request, exception):
print(exception)
print("mid1 中的process_exception")
# return HttpResponse(exception)
class mid2(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid2裏面的 process_request")
def process_response(self, request, response):
print("mid2裏面的 process_response")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("mid2 中的process_view")
def process_exception(self, request, exception):
print(exception)
print("mid2 中的process_exception")
視圖函數沒有報錯的狀況,運行後的截圖爲:(process_exception方法沒有被觸發)
視圖函數有報錯的狀況:
頁面報錯,狀態碼爲500
若是去掉return HttpResponse(exception) 的註釋運行的到的狀態碼爲500,前端頁面返回不是報錯頁面,而是process_exception的返回值信息。
獲得運行流程圖爲:
process_template_response(self, request, response)
該方法參數:
HttpRequest對象
response是TemplateResponse對象(由視圖函數或者中間件產生)。
process_template_response是在視圖函數執行完成後當即執行,可是它有一個前提條件,那就是視圖函數返回的對象有一個render()方法(或者代表該對象是一個TemplateResponse對象或等價方法)。
例子:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# by hsz
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class mid1(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid1裏面的 process_request")
# return HttpResponse("mId1__request方法")
def process_response(self, request, response):
print("mid1裏面的 process_response")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("mid1 中的process_view")
# return view_func(request)
def process_exception(self, request, exception):
print(exception)
print("mid1 中的process_exception")
# return HttpResponse(exception)
def process_template_response(self, request, response):
print("mid1 中的process_template_response")
return response
class mid2(MiddlewareMixin):
def process_request(self, request):
# 默認沒有返回值, 若是有返回值,會終止後面的中間件的執行,而且會直接返回當前類下的process_response方法.
print("mid2裏面的 process_request")
def process_response(self, request, response):
print("mid2裏面的 process_response")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("mid2 中的process_view")
def process_exception(self, request, exception):
print(exception)
print("mid2 中的process_exception")
def process_template_response(self, request, response):
print("mid2 中的process_template_response")
return response
views.py內容爲:
from django.shortcuts import render, HttpResponse
# Create your views here.
def index(request):
# int("aaa")
print("運行了index視圖函數。。。")
def render():
print("in index/render")
return HttpResponse("O98K")
rep = HttpResponse("OK")
rep.render = render
return rep
正常運行後端打印爲:
結果獲得:
視圖函數執行完以後,當即執行了中間件的process_template_response方法。