← Назад к вопросам
Как используется middleware в Django?
2.0 Middle🔥 231 комментариев
#Базы данных (NoSQL)#Тестирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как используется middleware в Django?
Middleware в Django — это система хуков, которые обрабатывают HTTP запросы и ответы на глобальном уровне. Это мощный механизм для реализации кросс-функциональной логики, которая применяется ко всем или некоторым запросам.
Основная концепция
Middleware работает как цепочка фильтров (middleware chain). Каждый middleware имеет возможность:
- process_request — обработать запрос ДО view
- process_view — обработать ПЕРЕД вызовом view
- process_response — обработать ПОСЛЕ view
- process_exception — обработать исключения
Порядок обработки запроса
HTTP запрос
↓
Middleware 1: process_request
↓
Middleware 2: process_request
↓
Middleware 1: process_view
↓
Middleware 2: process_view
↓
View
↓
Middleware 2: process_response
↓
Middleware 1: process_response
↓
HTTP ответ
1. Создание простого middleware
# middleware.py
from django.utils.deprecation import MiddlewareMixin
import logging
logger = logging.getLogger(__name__)
class LoggingMiddleware(MiddlewareMixin):
"""Логирование всех запросов"""
def process_request(self, request):
"""Обработать входящий запрос"""
logger.info(f"Новый запрос: {request.method} {request.path}")
# request.start_time = time.time() # Для измерения времени
return None # Продолжить обработку
def process_view(self, request, view_func, view_args, view_kwargs):
"""Обработать перед вызовом view функции"""
logger.info(f"Вызываю view: {view_func.__name__}")
return None # None означает продолжить обработку
def process_response(self, request, response):
"""Обработать ответ"""
logger.info(f"Ответ: {response.status_code}")
return response # ВСЕГДА возвращаем response
def process_exception(self, request, exception):
"""Обработать исключение"""
logger.error(f"Ошибка: {exception}", exc_info=True)
return None # None передаёт исключение дальше
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'myapp.middleware.LoggingMiddleware', # Наш middleware
'django.middleware.common.CommonMiddleware',
]
2. Middleware для аутентификации
from django.contrib.auth.models import AnonymousUser
from django.utils.functional import SimpleLazyObject
from functools import wraps
import jwt
class JWTAuthMiddleware(MiddlewareMixin):
"""Аутентификация через JWT токен"""
def process_request(self, request):
# Получаем токен из заголовка
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
if not auth_header.startswith('Bearer '):
request.user = AnonymousUser()
return None
token = auth_header[7:] # Убираем "Bearer "
try:
# Декодируем JWT токен
payload = jwt.decode(token, 'secret-key', algorithms=['HS256'])
user_id = payload.get('user_id')
# Получаем пользователя
from django.contrib.auth.models import User
request.user = User.objects.get(id=user_id)
except (jwt.InvalidTokenError, User.DoesNotExist):
request.user = AnonymousUser()
return None
3. Middleware для CORS
class CORSMiddleware(MiddlewareMixin):
"""Разрешить кросс-доменные запросы"""
ALLOWED_ORIGINS = [
'http://localhost:3000',
'https://example.com',
]
def process_request(self, request):
# Обработка preflight запросов
if request.method == 'OPTIONS':
return self.get_cors_response(request)
return None
def process_response(self, request, response):
origin = request.META.get('HTTP_ORIGIN')
if origin in self.ALLOWED_ORIGINS:
response['Access-Control-Allow-Origin'] = origin
response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
response['Access-Control-Allow-Credentials'] = 'true'
return response
def get_cors_response(self, request):
from django.http import HttpResponse
response = HttpResponse()
response['Access-Control-Allow-Origin'] = request.META.get('HTTP_ORIGIN', '')
response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
return response
4. Middleware для кэширования
from django.core.cache import cache
import hashlib
class CacheMiddleware(MiddlewareMixin):
"""Кэширование GET запросов"""
CACHE_TIMEOUT = 60 * 5 # 5 минут
def process_request(self, request):
# Кэшируем только GET запросы
if request.method != 'GET':
return None
# Генерируем ключ кэша
cache_key = self._get_cache_key(request)
# Проверяем кэш
cached_response = cache.get(cache_key)
if cached_response:
print(f"Вернули из кэша: {request.path}")
return cached_response
# Сохраняем ключ в request для process_response
request.cache_key = cache_key
return None
def process_response(self, request, response):
# Кэшируем успешные ответы
if hasattr(request, 'cache_key') and response.status_code == 200:
cache.set(request.cache_key, response, self.CACHE_TIMEOUT)
return response
@staticmethod
def _get_cache_key(request):
"""Генерировать уникальный ключ кэша"""
key_string = f"{request.path}?{request.GET.urlencode()}"
return f"cache:{hashlib.md5(key_string.encode()).hexdigest()}"
5. Middleware для мониторинга производительности
import time
from django.core.mail import mail_admins
class PerformanceMiddleware(MiddlewareMixin):
"""Отслеживание медленных запросов"""
SLOW_REQUEST_THRESHOLD = 1.0 # 1 секунда
def process_request(self, request):
request.start_time = time.time()
return None
def process_response(self, request, response):
if not hasattr(request, 'start_time'):
return response
duration = time.time() - request.start_time
# Логируем медленные запросы
if duration > self.SLOW_REQUEST_THRESHOLD:
message = (
f"Медленный запрос!\n"
f"URL: {request.path}\n"
f"Метод: {request.method}\n"
f"Время: {duration:.2f}с\n"
f"Статус: {response.status_code}"
)
mail_admins("Медленный запрос", message)
# Добавляем заголовок с временем обработки
response['X-Process-Time'] = f"{duration:.2f}s"
return response
6. Middleware для проверки прав доступа
from django.http import JsonResponse
from django.urls import resolve
class PermissionMiddleware(MiddlewareMixin):
"""Проверка прав доступа до view"""
# Эндпоинты, требующие аутентификации
PROTECTED_PATHS = [
'/api/admin/',
'/api/user/profile/',
]
# Публичные эндпоинты
PUBLIC_PATHS = [
'/api/auth/login/',
'/api/auth/register/',
'/health/',
]
def process_view(self, request, view_func, view_args, view_kwargs):
# Проверяем публичные пути
if any(request.path.startswith(p) for p in self.PUBLIC_PATHS):
return None
# Проверяем защищённые пути
if any(request.path.startswith(p) for p in self.PROTECTED_PATHS):
if not request.user.is_authenticated:
return JsonResponse(
{'error': 'Требуется аутентификация'},
status=401
)
# Проверяем admin права
if '/admin/' in request.path and not request.user.is_staff:
return JsonResponse(
{'error': 'Недостаточно прав'},
status=403
)
return None
7. Middleware для обработки ошибок
from django.http import JsonResponse
import traceback
class ErrorHandlingMiddleware(MiddlewareMixin):
"""Обработка необработанных ошибок"""
def process_exception(self, request, exception):
# Логируем исключение
logger.error(
f"Необработанная ошибка: {exception}",
exc_info=True,
extra={'request': request}
)
# Отправляем управляемый ответ
if request.path.startswith('/api/'):
return JsonResponse(
{
'error': 'Внутренняя ошибка сервера',
'type': exception.__class__.__name__,
},
status=500
)
# Для обычных страниц оставляем обработку Django
return None
8. Middleware для трассировки запросов
import uuid
from contextvars import ContextVar
request_id = ContextVar('request_id', default=None)
class RequestIDMiddleware(MiddlewareMixin):
"""Добавить уникальный ID для каждого запроса"""
def process_request(self, request):
# Генерируем или получаем ID
trace_id = str(uuid.uuid4())
request.trace_id = trace_id
request_id.set(trace_id)
return None
def process_response(self, request, response):
if hasattr(request, 'trace_id'):
response['X-Trace-ID'] = request.trace_id
return response
# Использование в логировании
import logging
class TraceIDFilter(logging.Filter):
def filter(self, record):
record.trace_id = request_id.get() or 'unknown'
return True
logger = logging.getLogger(__name__)
logger.addFilter(TraceIDFilter())
Порядок встроенных middleware в Django
# settings.py (по умолчанию)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', # HTTPS redirect
'django.contrib.sessions.middleware.SessionMiddleware', # Sessions
'django.middleware.common.CommonMiddleware', # URL normalization
'django.middleware.csrf.CsrfViewMiddleware', # CSRF protection
'django.contrib.auth.middleware.AuthenticationMiddleware', # Authentication
'django.contrib.messages.middleware.MessageMiddleware', # Messages
'django.middleware.clickjacking.XFrameOptionsMiddleware', # Clickjacking
]
Важные правила
- process_request может вернуть HttpResponse (прерывает цепь)
- process_response ДОЛЖЕН вернуть HttpResponse
- process_exception может вернуть HttpResponse
- Middleware выполняются в порядке settings.MIDDLEWARE
- Response middleware выполняются в ОБРАТНОМ порядке
Пример сложного middleware
class ComplexMiddleware(MiddlewareMixin):
"""Комплексный middleware с несколькими функциями"""
def process_request(self, request):
# 1. Добавляем трассировку
request.request_id = str(uuid.uuid4())
request.start_time = time.time()
# 2. Проверяем率限
if self._is_rate_limited(request):
return JsonResponse({'error': 'Rate limit exceeded'}, status=429)
return None
def process_view(self, request, view_func, view_args, view_kwargs):
# Проверяем требования к аутентификации
if hasattr(view_func, 'require_auth') and not request.user.is_authenticated:
return JsonResponse({'error': 'Unauthorized'}, status=401)
return None
def process_response(self, request, response):
# Добавляем заголовки
response['X-Request-ID'] = request.request_id
response['X-Process-Time'] = str(time.time() - request.start_time)
return response
def _is_rate_limited(self, request):
# Логика rate limiting
return False
Выводы
Middleware в Django используется для:
- Аутентификации и авторизации (JWT, session)
- Логирования и мониторинга (производительность, ошибки)
- Кэширования (GET запросы)
- CORS и безопасности (заголовки, CSRF)
- Обработки ошибок (глобальный error handler)
- Трассировки (request ID, context)
Это мощный инструмент для реализации кросс-функциональной логики без дублирования кода во всех view функциях.