Django Middleware Nâng Cao 2026: Custom Middleware, Logging và Câu Hỏi Phỏng Vấn

Hướng dẫn toàn diện về Django middleware năm 2026 bao gồm cách tạo custom middleware, triển khai logging hiệu quả, và các câu hỏi phỏng vấn thường gặp dành cho lập trình viên Django cấp cao.

Sơ đồ kiến trúc Django middleware thể hiện luồng request-response

Django middleware nằm ở trung tâm của mọi chu trình request-response, tuy nhiên nhiều lập trình viên vẫn coi nó như một hộp đen. Hiểu rõ cách middleware thực thi, khi nào nên viết custom middleware, và cách triển khai logging ở tầng middleware là điều phân biệt giữa lập trình viên Django senior và junior trong các cuộc phỏng vấn kỹ thuật.

Django 6.0 Middleware

Django 6.0 hỗ trợ đầy đủ async middleware với cú pháp async/await native. Thiết lập async_capable = Truesync_capable = False trên middleware class để xử lý request mà không có overhead từ thread.

Cách Django Middleware Thực Thi Trong Chu Trình Request-Response

Middleware trong Django tuân theo mô hình "onion" (củ hành). Khi request đến, nó đi qua từng middleware trong MIDDLEWARE từ trên xuống dưới. Khi view trả về response, response đi ngược lại qua middleware từ dưới lên trên. Thứ tự này rất quan trọng: middleware cần dữ liệu session phải chạy sau SessionMiddleware.

Cấu hình MIDDLEWARE mặc định trong Django 6.0:

python
# 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",
]

Mỗi middleware có thể cắt ngắn chuỗi bằng cách trả về HttpResponse trực tiếp thay vì gọi get_response(). Khi điều này xảy ra, middleware bên trong và view không bao giờ được thực thi, nhưng middleware bên ngoài vẫn xử lý response.

Viết Custom Middleware Dựa Trên Class Trong Django 6.0

Mẫu middleware hiện đại yêu cầu một class với các method __init____call__. Method __init__ chạy một lần khi server khởi động, trong khi __call__ chạy cho mỗi request.

python
# middleware/timing.py
import time
import logging

logger = logging.getLogger(__name__)

class RequestTimingMiddleware:
    """Ghi lại thời gian xử lý mỗi request."""

    def __init__(self, get_response):
        # Được gọi một lần khi server khởi động
        self.get_response = get_response

    def __call__(self, request):
        # Code trước khi view thực thi
        start_time = time.perf_counter()

        # Gọi middleware tiếp theo hoặc view
        response = self.get_response(request)

        # Code sau khi view thực thi
        duration_ms = (time.perf_counter() - start_time) * 1000
        logger.info(
            "Request %s %s hoàn thành trong %.2fms",
            request.method,
            request.path,
            duration_ms
        )

        return response

Đăng ký middleware trong settings.py bằng cách thêm import path vào MIDDLEWARE. Vị trí rất quan trọng: đặt timing middleware ở đầu danh sách để đo toàn bộ vòng đời request.

Async Middleware Cho Ứng Dụng Django High-Concurrency

Django 6.0 xử lý async request một cách native. Đối với ứng dụng chạy dưới ASGI với async views, sync middleware tạo ra bottleneck hiệu năng vì Django bọc sync middleware trong thread pool executors. Viết async middleware loại bỏ overhead này.

python
# middleware/async_timing.py
import time
import logging
from asgiref.sync import iscoroutinefunction, markcoroutinefunction

logger = logging.getLogger(__name__)

class AsyncRequestTimingMiddleware:
    """Async-native timing middleware cho deployment ASGI."""

    async_capable = True
    sync_capable = False

    def __init__(self, get_response):
        self.get_response = get_response
        if iscoroutinefunction(self.get_response):
            markcoroutinefunction(self)

    async def __call__(self, request):
        start_time = time.perf_counter()

        # Await middleware tiếp theo hoặc async view
        response = await self.get_response(request)

        duration_ms = (time.perf_counter() - start_time) * 1000
        logger.info(
            "Async request %s %s hoàn thành trong %.2fms",
            request.method,
            request.path,
            duration_ms
        )

        return response

Decorator @sync_and_async_middleware từ django.utils.decorators tạo middleware xử lý cả request sync và async bằng cách kiểm tra iscoroutinefunction(get_response) tại runtime.

Triển Khai Request ID Logging Middleware

Tương quan log trong hệ thống phân tán yêu cầu một identifier duy nhất cho mỗi request. Mẫu này thường xuất hiện trong câu hỏi phỏng vấn Django vì nó thể hiện sự hiểu biết về middleware, logging, và debug hệ thống production.

python
# middleware/request_id.py
import uuid
import logging

class RequestIDMiddleware:
    """Gắn request ID duy nhất vào mỗi request để tương quan log."""

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

    def __call__(self, request):
        # Tạo hoặc trích xuất request ID từ header
        request_id = request.headers.get("X-Request-ID")
        if not request_id:
            request_id = str(uuid.uuid4())

        # Gắn vào object request để truy cập trong views
        request.request_id = request_id

        response = self.get_response(request)

        # Thêm request ID vào response headers
        response["X-Request-ID"] = request_id

        return response

Để bao gồm request_id trong tất cả các thông điệp log, tạo một logging filter tùy chỉnh:

python
# logging_filters.py
import logging

class RequestIDFilter(logging.Filter):
    """Chèn request_id vào log records."""

    def filter(self, record):
        from django.middleware.request_id import local
        record.request_id = getattr(local, "request_id", "no-request-id")
        return True

Cấu hình filter trong settings.py:

python
# settings.py
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "filters": {
        "request_id": {
            "()": "logging_filters.RequestIDFilter",
        },
    },
    "formatters": {
        "verbose": {
            "format": "[{levelname}] {asctime} [{request_id}] {name}: {message}",
            "style": "{",
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "verbose",
            "filters": ["request_id"],
        },
    },
    "root": {
        "handlers": ["console"],
        "level": "INFO",
    },
}

Sẵn sàng chinh phục phỏng vấn Django?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Hook Method Middleware Để Kiểm Soát Chi Tiết

Ngoài __call__, Django middleware hỗ trợ ba hook method: process_view, process_exception, và process_template_response. Các method này cung cấp khả năng kiểm soát tại các điểm cụ thể trong vòng đời request.

process_view Cho Logic Pre-Execution

python
# middleware/permission_check.py
from django.http import HttpResponseForbidden

class PermissionCheckMiddleware:
    """Kiểm tra quyền trước khi thực thi view."""

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

    def __call__(self, request):
        return self.get_response(request)

    def process_view(self, request, view_func, view_args, view_kwargs):
        # Truy cập metadata của view
        required_permission = getattr(view_func, "required_permission", None)

        if required_permission:
            if not request.user.has_perm(required_permission):
                return HttpResponseForbidden("Permission denied")

        # Return None để tiếp tục đến view
        return None

Mẫu này cho phép decorate views với các yêu cầu permission:

python
# views.py
def require_permission(perm):
    def decorator(view_func):
        view_func.required_permission = perm
        return view_func
    return decorator

@require_permission("app.can_edit")
def edit_resource(request, pk):
    # Logic view
    pass

process_exception Cho Error Handling Tập Trung

python
# middleware/error_tracking.py
import logging
import traceback

logger = logging.getLogger(__name__)

class ErrorTrackingMiddleware:
    """Ghi lại exception với đầy đủ ngữ cảnh trước khi Django xử lý."""

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

    def __call__(self, request):
        return self.get_response(request)

    def process_exception(self, request, exception):
        logger.error(
            "Unhandled exception trong %s %s: %s\n%s",
            request.method,
            request.path,
            str(exception),
            traceback.format_exc(),
            extra={
                "user_id": getattr(request.user, "id", None),
                "request_id": getattr(request, "request_id", None),
            }
        )
        # Return None để Django xử lý exception
        return None

Các method process_exception của middleware thực thi theo thứ tự ngược lại. Nếu một middleware trả về HttpResponse, middleware ở trước trong stack sẽ không thấy exception.

Cập Nhật Security Middleware Django 6.0

Django 6.0 đi kèm với một số bản vá bảo mật cho UpdateCacheMiddleware. Theo Django security releases từ 2026, response với Cache-Control: private sử dụng mixed case bị cache sai, và response cho request có header Authorization có thể được lưu trong shared caches.

LoginRequiredMiddleware, được giới thiệu trong Django 5.1, bắt buộc xác thực toàn site:

python
# settings.py
MIDDLEWARE = [
    # ... middleware khác
    "django.contrib.auth.middleware.LoginRequiredMiddleware",
]

# Miễn trừ view cụ thể
from django.contrib.auth.decorators import login_not_required

@login_not_required
def public_view(request):
    return HttpResponse("Nội dung công khai")

Điều này đảo ngược mẫu truyền thống decorate protected views với @login_required. Đối với ứng dụng mà hầu hết views yêu cầu xác thực, điều này giảm boilerplate và ngăn ngừa việc vô tình expose endpoint được bảo vệ.

MiddlewareMixin và Migration Từ Legacy Middleware

MiddlewareMixin kết nối middleware kiểu cũ (sử dụng method process_requestprocess_response) với mẫu callable mới. Lưu ý rằng django.utils.deprecation.MiddlewareMixin đã deprecated và sẽ bị xóa trong Django 6.2. Sử dụng django.middleware.MiddlewareMixin thay thế.

python
# middleware/legacy_style.py
from django.middleware import MiddlewareMixin

class LegacyStyleMiddleware(MiddlewareMixin):
    """Middleware sử dụng mẫu hook-based legacy."""

    def process_request(self, request):
        # Được gọi trước view, return None để tiếp tục
        request.custom_attribute = "value"
        return None

    def process_response(self, request, response):
        # Được gọi sau view, phải return response
        response["X-Custom-Header"] = "middleware-added"
        return response

Đối với middleware mới, tránh MiddlewareMixin. Mẫu callable cung cấp luồng điều khiển rõ ràng hơn và tương thích tốt hơn với async Django.

Câu Hỏi Phỏng Vấn Django Middleware Phổ Biến

Các cuộc phỏng vấn kỹ thuật thường bao gồm câu hỏi về middleware để đánh giá sự hiểu biết về vòng đời request của Django. Những câu hỏi này thường xuất hiện trong phỏng vấn lập trình viên Django senior.

H: Sự khác biệt giữa thứ tự middleware và thứ tự thực thi cho response là gì?

Middleware xử lý request từ trên xuống dưới qua MIDDLEWARE nhưng xử lý response từ dưới lên trên. Hãy tưởng tượng như củ hành: middleware ngoài cùng là middleware đầu tiên thấy request và cuối cùng thấy response.

H: Middleware short-circuiting hoạt động như thế nào?

Khi middleware trả về HttpResponse thay vì gọi get_response(), request không bao giờ đến được middleware bên trong hoặc view. Response vẫn đi qua tất cả middleware bên ngoài trên đường về. Hành vi này khác với setting MIDDLEWARE_CLASSES legacy, nơi tất cả method process_response chạy bất kể short-circuiting.

H: Khi nào middleware nên truy cập request.user?

Chỉ sau khi AuthenticationMiddleware đã chạy. Truy cập request.user trước khi authentication middleware gắn nó sẽ gây ra AttributeError. Đặt custom middleware cần thông tin user sau AuthenticationMiddleware trong danh sách MIDDLEWARE.

H: Làm thế nào để middleware tương thích với async?

Thiết lập async_capable = True trên middleware class và triển khai __call__ như một async method sử dụng await get_response(request). Đối với middleware phải hoạt động trong cả ngữ cảnh sync và async, sử dụng @sync_and_async_middleware và kiểm tra iscoroutinefunction(get_response) để phân nhánh phù hợp.

Bắt đầu luyện tập!

Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.

Thành Thạo Django Middleware Cho Production và Phỏng Vấn

Django middleware kiểm soát các cross-cutting concerns bao trùm toàn bộ vòng đời request. Các điểm quan trọng khi làm việc với middleware trong Django 6.0:

  • Middleware thực thi theo mẫu onion: request chảy từ trên xuống, response chảy từ dưới lên
  • Thiết lập async_capable = True cho async-native middleware trong deployment ASGI để tránh overhead thread pool
  • Sử dụng process_view để kiểm tra metadata view trước khi thực thi, process_exception cho logging error tập trung
  • Request ID middleware cho phép tương quan log giữa các service phân tán, một yêu cầu phổ biến trong production
  • LoginRequiredMiddleware đảo ngược mẫu xác thực: views được bảo vệ theo mặc định, views công khai được miễn trừ rõ ràng
  • django.utils.deprecation.MiddlewareMixin deprecated sẽ chuyển sang django.middleware.MiddlewareMixin trong Django 6.2
  • Thứ tự middleware quyết định component nào thấy request.user, dữ liệu session, và các thuộc tính request khác

Để tìm hiểu sâu hơn về các mẫu Django ORM và REST framework, xem hướng dẫn tối ưu Django ORM.

Thử thách hôm nay

Bạn có tìm ra lỗi trong Django không?

Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Anthony Fillion-Maillet

Viết bởi

Anthony Fillion-Maillet

Người sáng lập SharpSkill

Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.

Cập nhật ngày 18 tháng 9, 2026

Thẻ

#django
#middleware
#python
#logging
#interview

Chia sẻ

Bài viết liên quan