文章

Django - 中介軟體 (Middleware)

今天我們將學習 Django 中的重要組件——中介軟體(Middleware)。中介軟體是一種處理 HTTP 請求與回應的鉤子,能在請求到達視圖前、或回應送達瀏覽器前進行處理。通過中介軟體,我們可以實現請求攔截、回應修改、統計日誌等功能。


課程目標

  • 瞭解中介軟體的基本概念與工作原理。
  • 探索內建的中介軟體及其用途。
  • 實現自訂中介軟體來滿足特定需求。

課程內容

1. 中介軟體的基本概念

1.1 中介軟體的作用

中介軟體是一種處理 HTTP 請求與回應的組件,負責:

  • 攔截請求並執行操作,例如身份驗證、日誌記錄。
  • 改變請求對象或添加額外的上下文數據。
  • 改變回應內容或狀態碼。

1.2 中介軟體的處理流程

  1. 請求處理:

    • 請求從瀏覽器發出後,依次通過所有已註冊的中介軟體。
    • 每個中介軟體可對請求進行修改,或直接返回回應以中斷流程。
  2. 回應處理:

    • 視圖返回回應後,該回應會再依次通過所有中介軟體。
    • 每個中介軟體可以修改回應內容或狀態碼。

2. Django 的內建中介軟體

2.1 中介軟體列表

Django 預設的中介軟體可在 settings.py 中找到:

1
2
3
4
5
6
7
8
9
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 常見內建中介軟體

  • SecurityMiddleware

    • 提供安全相關的功能,例如強制 HTTPS。
  • SessionMiddleware

    • 處理用戶會話數據。
  • CommonMiddleware

    • 處理常見的 HTTP 功能,如 URL 規範化。
  • CsrfViewMiddleware

    • 防止跨站請求偽造(CSRF)攻擊。
  • AuthenticationMiddleware

    • 將當前的用戶信息附加到請求對象中。

3. 自訂中介軟體

3.1 自訂中介軟體的結構

每個中介軟體類別都需要實現以下方法之一:

  • __init__():在啟動時初始化中介軟體。
  • __call__():處理請求與回應。
  • process_request():在視圖執行前處理請求。
  • process_response():在回應返回前處理回應。

3.2 示例:請求日誌記錄

middleware.py 中新增一個自訂中介軟體:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import logging

logger = logging.getLogger(__name__)

class RequestLogMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 請求處理前的邏輯
        logger.info(f"Request Path: {request.path}, Method: {request.method}")

        response = self.get_response(request)

        # 回應處理後的邏輯
        return response

將其添加到 settings.pyMIDDLEWARE 中:

1
2
3
4
MIDDLEWARE = [
    # 其他中介軟體...
    'myapp.middleware.RequestLogMiddleware',
]

4. 高級中介軟體應用

4.1 防止惡意 IP 訪問

創建一個中介軟體來阻止特定 IP 的訪問:

1
2
3
4
5
6
7
8
9
10
11
class BlockIPMiddleware:
    BLOCKED_IPS = ['192.168.1.100', '10.0.0.1']

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.META['REMOTE_ADDR'] in self.BLOCKED_IPS:
            from django.http import HttpResponseForbidden
            return HttpResponseForbidden("您的 IP 已被禁止訪問。")
        return self.get_response(request)

4.2 在請求中添加額外數據

向每個請求對象中添加自訂屬性:

1
2
3
4
5
6
7
8
class AddCustomHeaderMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.custom_data = "這是額外的數據"
        response = self.get_response(request)
        return response

4.3 測試模式下模擬錯誤

模擬測試模式下的服務器錯誤:

1
2
3
4
5
6
7
8
class SimulateErrorMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path == '/simulate-error/':
            raise ValueError("模擬的服務器錯誤!")
        return self.get_response(request)

5. 實踐:訪問計數器

目標

在所有請求中統計網站的總訪問次數。

實作

middleware.py 中新增:

1
2
3
4
5
6
7
8
9
10
11
12
from django.utils.deprecation import MiddlewareMixin

class VisitCountMiddleware(MiddlewareMixin):
    visit_count = 0

    def process_request(self, request):
        VisitCountMiddleware.visit_count += 1
        request.visit_count = VisitCountMiddleware.visit_count

    def process_response(self, request, response):
        response['X-Visit-Count'] = VisitCountMiddleware.visit_count
        return response

在視圖中顯示訪問次數:

1
2
3
4
from django.http import JsonResponse

def visit_count_view(request):
    return JsonResponse({'visit_count': request.visit_count})

6. 本日總結

  • 瞭解了中介軟體的處理流程與作用。
  • 使用內建中介軟體實現常見功能。
  • 創建了多種自訂中介軟體應用,涵蓋日誌記錄、訪問限制、模擬錯誤等場景。

作業

  1. 建立一個中介軟體,記錄每個請求的處理時間。
  2. 創建一個中介軟體,攔截並重定向未登入用戶的所有請求到登入頁面。
  3. 在 Django 專案中實現一個「網站黑名單」功能,拒絕特定 IP 的請求。

本文章以 CC BY 4.0 授權