Django中间件Middleware详解:原理、配置与实战案例
本文深入解析Django中间件Middleware的工作原理、配置方法及执行顺序。通过MIDDLEWARE_CLASSES设置中间件,详解process_request与process_response的执行流程。提供流量统计、异常处理、移动端识别及本地化等实用中间件代码示例,帮助开发者掌握全局请求处理技巧。
中间件介绍
中间件(Middleware)位于请求(request)与响应(response)处理之间,属于轻量级的全局处理层,用于修改Django的输入与输出。由于其影响全局,使用时需谨慎,不当使用可能影响系统性能。
每个中间件通常负责特定功能,例如 负责会话(sessions)处理。
激活中间件
需在 settings.py 配置文件中配置 MIDDLEWARE_CLASSES 列表。
MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
若无需使用任何中间件,可将该列表设为空。
中间件顺序
浏览器发出的请求(Request)经Django处理后返回响应(HttpResponse),其传递过程涉及 process_request 和 process_response 的执行,两者顺序相反,具体流程如图所示:

每个请求首先经过中间件的 process_request 函数,该函数返回 None 或 HttpResponse 对象。若返回 None,则继续处理后续中间件;若返回 HttpResponse 对象,则中断处理并直接返回给网页。中间件无需继承特定类(可继承 object),其基本结构如下:
class CommonMiddleware(object): def process_request(self, request): return None def process_response(self, request, response): return response
中间件涉及以下几个关键钩子(hook):
- process_request()
- process_exception()(仅当视图抛出异常时调用)
- process_template_response()
- process_response()
常用的内置中间件组件包括:
1. Sessions(会话处理)
2. Authentication(身份认证)
3. CSRF Protection(跨站请求伪造保护)
4. GZipping Content(内容压缩)
例如,若需实现流量统计功能:
class BlockedIpMiddleware(object): def process_request(self, request): ...数据库拿access值 access = access+1 ...存起来,类似这个原理
上述代码实现简单的访问计数累加,需将该中间件的Python路径写入 settings.py 中。
MIDDLEWARE_CLASSES = ( 'zjj.middleware.BlockedIpMiddleware', ...其它的中间件 )
Django 会按照 MIDDLEWARE_CLASSES 中从上到下的顺序依次执行各中间件的 process_request 函数,而 process_response 函数的执行顺序则与注册顺序相反,即最前面的中间件最后执行。
二、在服务器正式运行后,通常将 DEBUG 设置为 False 以提升安全性,但这会导致错误详情页面无法显示。如何同时兼顾安全与错误调试?
普通访问者看到的是友好的错误提示信息。
管理员则可以看到详细的错误信息,以便修复BUG。
利用中间件可以实现这一需求,代码如下:
import sys
from django.views.debug import technical_500_response
from django.conf import settings
class UserBasedExceptionMiddleware(object):
def process_exception(self, request, exception):
if request.user.is_superuser or request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
return technical_500_response(request, *sys.exc_info())
将该中间件添加到 settings.py 的 MIDDLEWARE_CLASSES 中,建议置于列表末尾,以便观察其他中间件的 process_request 错误。
当访问者为管理员时,系统会返回错误详情,例如访问不存在的页面时。
普通用户看到的是标准的 404 错误页面,而管理员则能看到详细报错信息。
三、分享一个识别移动设备的中间件,更详细的实现可参考 django-mobi 项目。
MOBILE_USERAGENTS = ("2.0 MMP","240x320","400X240","AvantGo","BlackBerry",
"Blazer","Cellphone","Danger","DoCoMo","Elaine/3.0","EudoraWeb",
"Googlebot-Mobile","hiptop","IEMobile","KYOCERA/WX310K","LG/U990",
"MIDP-2.","MMEF20","MOT-V","NetFront","Newt","Nintendo Wii","Nitro",
"Nokia","Opera Mini","Palm","PlayStation Portable","portalmmm","Proxinet",
"ProxiNet","SHARP-TQ-GX10","SHG-i900","Small","SonyEricsson","Symbian OS",
"SymbianOS","TS21i-10","UP.Browser","UP.Link","webOS","Windows CE",
"WinWAP","YahooSeeker/M1A1-R2D2","iPhone","iPod","Android",
"BlackBerry9530","LG-TU915 Obigo","LGE VX","webOS","Nokia5800")
class MobileTemplate(object):
"""
If a mobile user agent is detected, inspect the default args for the view
func, and if a template name is found assume it is the template arg and
attempt to load a mobile template based on the original template name.
"""
def process_view(self, request, view_func, view_args, view_kwargs):
if any(ua for ua in MOBILE_USERAGENTS if ua in
request.META["HTTP_USER_AGENT"]):
template = view_kwargs.get("template")
if template is None:
for default in view_func.func_defaults:
if str(default).endswith(".html"):
template = default
if template is not None:
template = template.rsplit(".html", 1)[0] + ".mobile.html"
try:
get_template(template)
except TemplateDoesNotExist:
pass
else:
view_kwargs["template"] = template
return view_func(request, *view_args, **view_kwargs)
return None
再举一个本地化(Localization)中间件的例子:
class LocaleMiddleware(object): def process_request(self, request): if 'locale' in request.cookies: request.locale = request.cookies.locale else: request.locale = None def process_response(self, request, response): if getattr(request, 'locale', False): response.cookies['locale'] = request.locale
该中间件将 cookies 中的 locale 值赋给 request 中的 locale 属性,供后续视图使用。
本部分参考了 Django 官方文档及网络教程,感谢各位前辈的分享。
总结
以上就是本文的全部内容,希望本文对您的学习或工作有所帮助。如有疑问欢迎留言交流,感谢支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













