# 第二節:中間件
# 中間件
中間件是在`request`和`response`處理過程中的一個插件。比如在`request`到達視圖函數之前,我們可以使用中間件來做一些相關的事情,比如可以判斷當前這個用戶有沒有登錄,如果登錄了,就綁定一個`user`對象到`request`上。也可以在`response`到達瀏覽器之前,做一些相關的處理,比如想要統一在`response`上設置一些`cookie`信息等。
## 自定義中間件:
中間件所處的位置沒有規定。只要是放到項目當中即可。一般分為兩種情況,如果中間件是屬于某個`app`的,那么可以在這個`app`下面創建一個`python`文件用來存放這個中間件,也可以專門創建一個`Python`包,用來存放本項目的所有中間件。創建中間件有兩種方式,一種是使用函數,一種是使用類,接下來對這兩種方式做個介紹:
### 使用函數的中間件:
```
<pre class="calibre12">```
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">simple_middleware</span><span class="hljs-params">(get_response)</span>:</span>
<span class="hljs-title"># 這個中間件初始化的代碼</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">middleware</span><span class="hljs-params">(request)</span>:</span>
<span class="hljs-title"># request到達view的執行代碼</span>
response = get_response(request)
<span class="hljs-title"># response到達瀏覽器的執行代碼</span>
<span class="hljs-keyword">return</span> response
<span class="hljs-keyword">return</span> middleware
```
```
### 使用類的中間件:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SimpleMiddleware</span><span class="hljs-params">(object)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, get_response)</span>:</span>
self.get_response = get_response
<span class="hljs-title"># 這個中間件初始化的代碼</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span><span class="hljs-params">(self, request)</span>:</span>
<span class="hljs-title"># request到達view之前執行的代碼</span>
response = self.get_response(request)
<span class="hljs-title"># response到達用戶瀏覽器之前執行的代碼</span>
<span class="hljs-keyword">return</span> response
```
```
在寫完中間件后,還需要在`settings.MIDDLEWARES`中配置寫好的中間件才可以使用。比如我們寫了一個在`request`到達視圖函數之前,判斷這個用戶是否登錄,如果已經登錄就綁定一個`user`對象到`request`上的中間件,這個中間件放在當前項目的`middlewares.users`下:
```
<pre class="calibre12">```
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_middleware</span><span class="hljs-params">(get_response)</span>:</span>
<span class="hljs-title"># 這個中間件初始化的代碼</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">middleware</span><span class="hljs-params">(request)</span>:</span>
<span class="hljs-title"># request到達view的執行代碼</span>
userid = request.session.get(<span class="hljs-string">"userid"</span>)
userModel = FrontUser.objects.filter(pk=userid).first()
<span class="hljs-keyword">if</span> userModel:
setattr(request,<span class="hljs-string">'frontuser'</span>,userModel)
response = get_response(request)
<span class="hljs-title"># response到達瀏覽器的執行代碼</span>
<span class="hljs-keyword">return</span> response
<span class="hljs-keyword">return</span> middleware
```
```
那么就可以在`settings.MIDDLEWARES`下做以下配置:
```
<pre class="calibre12">```
MIDDLEWARE = [
<span class="hljs-string">'django.middleware.security.SecurityMiddleware'</span>,
<span class="hljs-string">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
<span class="hljs-string">'django.middleware.common.CommonMiddleware'</span>,
<span class="hljs-string">'django.middleware.csrf.CsrfViewMiddleware'</span>,
<span class="hljs-string">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
<span class="hljs-string">'django.contrib.messages.middleware.MessageMiddleware'</span>,
<span class="hljs-string">'django.middleware.clickjacking.XFrameOptionsMiddleware'</span>,
<span class="hljs-string">'middlewares.users.user_middleware'</span>
]
```
```
中間件的執行是有順序的,他會根據在`MIDDLEWARE`中存放的順序來執行。因此如果有些中間件是需要基于其他中間件的,那么就需要放在其他中間件的后面來執行。
## Django內置的中間件:
1. `django.middleware.common.CommonMiddleware`:通用中間件。他的作用如下:
- 限制`settings.DISALLOWED_USER_AGENTS`中指定的請求頭來訪問本網站。`DISALLOWED_USER_AGENT`是一個正則表達式的列表。示例代碼如下:```
<pre class="calibre12">```
<span class="hljs-keyword">import</span> re
DISALLOWED_USER_AGENTS = [
re.compile(<span class="hljs-string">r'^\s$|^$'</span>),
re.compile(<span class="hljs-string">r'.*PhantomJS.*'</span>)
]
```
```
- 如果開發者在定義`url`的時候,最后有一個斜杠。但是用戶在訪問`url`的時候沒有提交這個斜杠,那么`CommonMiddleware`會自動的重定向到加了斜杠的`url`上去。
2. `django.middleware.gzip.GZipMiddleware`:將響應數據進行壓縮。如果內容長度少于200個長度,那么就不會壓縮。
3. `django.contrib.messages.middleware.MessageMiddleware`:消息處理相關的中間件。
4. `django.middleware.security.SecurityMiddleware`:做了一些安全處理的中間件。比如設置`XSS`防御的請求頭,比如做了`http`協議轉`https`協議的工作等。
5. `django.contrib.sessions.middleware.SessionMiddleware`:`session`中間件。會給`request`添加一個處理好的`session`對象。
6. `django.contrib.auth.middleware.AuthenticationMiddleware`:會給`request`添加一個`user`對象的中間件。
7. `django.middleware.csrf.CsrfViewMiddleware`:`CSRF`保護的中間件。
8. `django.middleware.clickjacking.XFrameOptionsMiddleware`:做了`clickjacking`攻擊的保護。`clickjacking`保護是攻擊者在自己的病毒網站上,寫一個誘惑用戶點擊的按鈕,然后使用`iframe`的方式將受攻擊的網站(比如銀行網站)加載到自己的網站上去,并將其設置為透明的,用戶就看不到,然后再把受攻擊的網站(比如銀行網站)的轉賬按鈕定位到病毒網站的按鈕上,這樣用戶在點擊病毒網站上按鈕的時候,實際上點擊的是受攻擊的網站(比如銀行網站)上的按鈕,從而實現了在不知不覺中給攻擊者轉賬的功能。
9. 緩存中間件:用來緩存一些頁面的。
- `django.middleware.cache.UpdateCacheMiddleware`。
- `django.middleware.cache.FetchFromCacheMiddleware`。
## 內置中間件放置的順序:
1. `SecurityMiddleware`:應該放到最前面。因為這個中間件并不需要依賴任何其他的中間件。如果你的網站同時支持`http`協議和`https`協議,并且你想讓用戶在使用`http`協議的時候重定向到`https`協議,那么就沒有必要讓他執行下面一大串中間件再重定向,這樣效率更高。
2. `UpdateCacheMiddleware`:應該在`SessionMiddleware, GZipMiddleware, LocaleMiddleware`之前。
3. `GZipMiddleware`。
4. `ConditionalGetMiddleware`。
5. `SessionMiddleware`。
6. `LocaleMiddleware`。
7. `CommonMiddleware`。
8. `CsrfViewMiddleware`。
9. `AuthenticationMiddleware`。
10. `MessageMiddleware`。
11. `FetchFromCacheMiddleware`。
12. `FlatpageFallbackMiddleware`。
13. `RedirectFallbackMiddleware`。
- Introduction
- 第一章:學前準備
- 第一節:虛擬環境
- 第二節:準備工作
- 第三節:Django介紹
- 第四節:URL組成部分
- 第二章:URL與視圖
- 第一節:第一個Django項目
- 第二節:視圖與URL分發器
- 第三章:模板
- 第一節:模板介紹
- 第二節:模板變量
- 第三節:常用標簽
- 第四節:常用過濾器
- 第五節:自定義過濾器
- 第七節:模版結構優化
- 第八節:加載靜態文件
- 第四章:數據庫
- 第一節:MySQL相關軟件
- 第二節:數據庫操作
- 第三節:ORM模型
- 第四節:模型常用字段
- 第五節:外鍵和表關系
- 第六節:增刪改查操作
- 第七節:查詢操作
- 第八節:QuerySet API
- 第九節:ORM模型遷移
- 第十節:ORM作業
- 第十一節:ORM作業參考答案
- 第十二節:Pycharm連接數據庫
- 第五章:視圖高級
- 第一節:限制請求method
- 第二節:頁面重定向
- 第三節:HttpRequest對象
- 第四節:HttpResponse對象
- 第五節:生成CSV文件
- 第六節:類視圖
- 第七節:錯誤處理
- 第六章:表單
- 第一節:表單概述
- 第二節:用表單驗證數據
- 第三節:ModelForm
- 第四節:文件上傳
- 第七章:cookie和session
- 第八章:上下文處理器和中間件
- 第一節:上下文處理器
- 第二節:中間件
- 第九章:安全
- 第一節:CSRF攻擊
- 第二節:XSS攻擊
- 第三節:點擊劫持攻擊
- 第四節:SQL注入
- 第十章:信號
- 第一節:什么是信號
- 第十一章:驗證和授權
- 第一節:概述
- 第二節:用戶對象
- 第三節:權限和分組
- 第十二章:Admin系統
- 第十三章:Django的緩存
- 第十四章:memcached
- 第十五章:Redis