Djangoin间件

LearningDjangoin间件 concepts, class型, 自定义in间件 and in 置in间件

in间件overview

in间件 is DjangoprocessingHTTPrequest and response hookframework. 它 is a 轻量级, low 级别 插件system, 用于全局改变Django 输入 or 输出.

in间件 in Djangorequest/responseprocessing过程in 位置:

  1. 当user发送HTTPrequest to Djangoapplication时, request首先经过所 has in间件 process_requestmethod (按照settings.pyinMIDDLEWARElist 顺序) .
  2. 然 after request to 达URLrouting, 被分发 to 相应 视graphfunction.
  3. 视graphfunctionprocessingrequest并返回HTTPresponse.
  4. response经过所 has in间件 process_responsemethod (按照settings.pyinMIDDLEWARElist 逆序) .
  5. 最 after response被发送回user 浏览器.

提示

in间件可以用于implementation many 种functions, such as身份verification, log记录, cache, 跨域resource共享 (CORS) etc..

in间件 class型

Djangoin间件可以分 for 以 under 几class:

  • in 置in间件: Djangoproviding 预定义in间件, such as身份verificationin间件, sessionin间件etc..
  • 自定义in间件: Development者根据需要creation in间件.
  • 第三方in间件: 由第三方Development者 or 组织providing in间件, such asDjango CORS Headers, Django Debug Toolbaretc..

in 置in间件

Djangoproviding了 many 种 in 置in间件, 用于processingcommon HTTPrequest and response. 以 under is 一些常用 in 置in间件:

SecurityMiddleware

providing了 many 种security增强functions, such as:

  • 设置X-XSS-Protection, X-Content-Type-Optionsetc.security头.
  • 强制HTTPS重定向.
  • 防止点击劫持攻击.

SessionMiddleware

managementusersession, providing了 in request之间storeuserdata mechanism.

CommonMiddleware

processingcommon HTTPfunctions, such as:

  • URL规范化 (添加/delete尾部斜杠) .
  • processingIf-Modified-Since头.
  • 设置Content-Length头.

CsrfViewMiddleware

providing跨站request伪造 (CSRF) 保护, 防止恶意网站伪造userrequest.

AuthenticationMiddleware

Userobject添加 to requestin, 方便 in 视graphin访问当 before loginuser.

MessageMiddleware

managementusermessage, 允许 in request之间store and retrieveusermessage.

XFrameOptionsMiddleware

防止点击劫持攻击, through设置X-Frame-Options头控制页面 is 否可以 in iframein显示.

自定义in间件

除了using in 置in间件 out , 还可以creation自定义in间件来implementationspecific functions.

in间件 creationmethod

in Django 1.10及以 on versionin, creationin间件 has 两种method:

  • 基于function in间件: usingfunction定义in间件, 接收get_responseparameter and requestparameter.
  • 基于class in间件: usingclass定义in间件, implementation__init__ and __call__method.

基于function in间件

# blog/middleware.py
from django.shortcuts import redirect

# 基于function in间件
def simple_middleware(get_response):
    # 一次性初始化code
    print("Simple middleware initialized")
    
    def middleware(request):
        # request to 达视graph之 before 执行 code
        print(f"Request: {request.method} {request.path}")
        
        # 调用视graphfunction, 获取response
        response = get_response(request)
        
        # 视graph返回response之 after 执行 code
        print(f"Response: {response.status_code}")
        
        return response
    
    return middleware

基于class in间件

# blog/middleware.py
class SimpleMiddleware:
    def __init__(self, get_response):
        # 一次性初始化code
        self.get_response = get_response
        print("Class-based middleware initialized")
    
    def __call__(self, request):
        # request to 达视graph之 before 执行 code
        print(f"Request: {request.method} {request.path}")
        
        # 调用视graphfunction, 获取response
        response = self.get_response(request)
        
        # 视graph返回response之 after 执行 code
        print(f"Response: {response.status_code}")
        
        return response

in间件 othermethod

基于class in间件还可以implementation以 under method, 用于processingspecific HTTPrequest and response阶段:

  • process_view(request, view_func, view_args, view_kwargs): in Django调用视graphfunction之 before 执行.
  • process_exception(request, exception): 当视graphfunction抛出exception时执行.
  • process_template_response(request, response): 当视graphfunction返回TemplateResponse or etc.价object时执行.

process_viewmethod

# blog/middleware.py
class ViewMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        return response
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        #  in 调用视graphfunction之 before 执行
        print(f"Calling view: {view_func.__name__} with args: {view_args}, kwargs: {view_kwargs}")
        # 可以返回HttpResponseobject, 提 before 结束request/response周期
        # return HttpResponse("Processed by process_view")

process_exceptionmethod

# blog/middleware.py
class ExceptionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        return response
    
    def process_exception(self, request, exception):
        # 当视graphfunction抛出exception时执行
        print(f"Exception occurred: {exception}")
        # 可以返回HttpResponseobject, processingexception
        # return HttpResponse(f"Error: {exception}", status=500)

process_template_responsemethod

# blog/middleware.py
class TemplateResponseMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        return response
    
    def process_template_response(self, request, response):
        # 当视graphfunction返回TemplateResponse时执行
        print(f"Processing template response: {response.template_name}")
        # 可以modifyresponseobject
        response.context_data['middleware_data'] = 'Added by middleware'
        return response

registerin间件

creationin间件 after , 需要 in settings.pyinregister:

# 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',
    # register自定义in间件
    'blog.middleware.SimpleMiddleware',
    'blog.middleware.ViewMiddleware',
    'blog.middleware.ExceptionMiddleware',
    'blog.middleware.TemplateResponseMiddleware',
]

in间件 执行顺序

in间件 执行顺序非常 important , 它决定了in间件processingrequest and response 顺序.

request阶段 执行顺序

当user发送HTTPrequest时, request按照settings.pyinMIDDLEWARElist 顺序依次经过每个in间件 process_request or __call__method (request to 达视graph之 before 部分) .

response阶段 执行顺序

当视graphfunction返回response时, response按照settings.pyinMIDDLEWARElist 逆序依次经过每个in间件 process_response or __call__method (视graph返回response之 after 部分) .

process_view, process_exception and process_template_response 执行顺序

  • process_view: 按照MIDDLEWARElist 顺序执行.
  • process_exception: 按照MIDDLEWARElist 逆序执行, 只 has 当视graphfunction抛出exception时才会执行.
  • process_template_response: 按照MIDDLEWARElist 逆序执行, 只 has 当视graphfunction返回TemplateResponse时才会执行.

warning

in间件 执行顺序会影响application behavior, 因此 in registerin间件时需要仔细考虑顺序. 例such as, 身份verificationin间件应该 in 需要访问userinformation in间件之 before register.

in间件 application场景

in间件可以用于implementation many 种functions, 以 under is 一些common application场景:

身份verification and authorization

可以usingin间件来verificationuser身份, 控制user for specificURL 访问permission.

# blog/middleware.py
from django.shortcuts import redirect

class AuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 不需要身份verification URL
        exempt_urls = ['/login/', '/register/', '/admin/']
        
        # checkuser is 否已login
        if not request.user.is_authenticated and request.path not in exempt_urls:
            return redirect('/login/')
        
        response = self.get_response(request)
        return response

log记录

可以usingin间件来记录所 has HTTPrequest and response 详细information, 便于debug and monitor.

# blog/middleware.py
import logging
from datetime import datetime

logger = logging.getLogger(__name__)

class LoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 记录requestinformation
        start_time = datetime.now()
        logger.info(f"Request: {request.method} {request.path} {request.META.get('REMOTE_ADDR')}")
        
        # 调用视graphfunction
        response = self.get_response(request)
        
        # 记录responseinformation
        duration = datetime.now() - start_time
        logger.info(f"Response: {response.status_code} {duration.total_seconds()}s")
        
        return response

cache

可以usingin间件来cacheHTTPresponse, improvingapplication performance.

# blog/middleware.py
from django.core.cache import cache
from django.http import HttpResponse

class CacheMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 只cacheGETrequest
        if request.method == 'GET':
            # 生成cache键
            cache_key = f"page:{request.path}"
            # 尝试 from cachein获取response
            cached_response = cache.get(cache_key)
            if cached_response:
                return HttpResponse(cached_response)
        
        # 调用视graphfunction
        response = self.get_response(request)
        
        # cacheGETrequest response
        if request.method == 'GET' and response.status_code == 200:
            cache.set(cache_key, response.content, 60 * 15)  # cache15分钟
        
        return response

跨域resource共享 (CORS)

可以usingin间件来implementation跨域resource共享, 允许不同域 before 端application访问Django API.

# blog/middleware.py
class CORSMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        
        # 设置CORS头
        response['Access-Control-Allow-Origin'] = '*'  # 允许所 has 域访问
        response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
        response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
        response['Access-Control-Max-Age'] = '86400'  # 预检request cache时间, 单位秒
        
        return response

in间件 best practices

  • 保持in间件简洁: in间件应该只processing单一functions, 避免 in 一个in间件inimplementation many 个不相关 functions.
  • 考虑performance影响: in间件会 in 每个HTTPrequest and responsein执行, 因此应该尽量reducingin间件 数量 and complexity, 避免影响application performance.
  • 注意执行顺序: in间件 执行顺序非常 important , 应该根据in间件 functions and 依赖relationships合理安排顺序.
  • using in 置in间件: 优先usingDjangoproviding in 置in间件, 它们经过了充分 test and optimization.
  • testin间件: writingtest用例来verificationin间件 functions and performance.

练习 1: creationlog记录in间件

  1. creation一个基于class in间件, 用于记录所 has HTTPrequest and response 详细information.
  2. 记录 informationincluding: requestmethod, URL, 客户端IP地址, responsestatus码, requestprocessing时间etc..
  3. 将loginformation写入file or datalibrary.
  4. in settings.pyinregisterin间件.
  5. testin间件 functions.

练习 2: creation身份verificationin间件

  1. creation一个基于function in间件, 用于verificationuser身份.
  2. for 于未login user, 将其重定向 to login页面.
  3. 允许某些URL (such aslogin页, register页) 不for身份verification.
  4. in settings.pyinregisterin间件.
  5. testin间件 functions.

练习 3: creationCORSin间件

  1. creation一个基于class in间件, 用于implementation跨域resource共享.
  2. 允许所 has 域访问API.
  3. 允许common HTTPmethod (GET, POST, PUT, DELETE, OPTIONS) .
  4. 允许common HTTP头 (Content-Type, Authorization) .
  5. in settings.pyinregisterin间件.
  6. testin间件 functions.