Django2.2中间件详解

中间件是Django用来处理请求和响应的钩子框架。它是一个轻量级的、底层级的“插件”系统,用于全局性地控制Django的输入或输出,可以理解为内置的app或者小框架。在django.core.handlers.base模块中定义了如何接入中间件,这也是学习Django源码的入口之一。每个中间件组件负责实现一些特定的功能。例如,Django包含一个中间件组件AuthenticationMiddlew...

Django2.2中间件详解

中间件是 Django 用来处理请求和响应的钩子框架。它是一个轻量级的、底层级的“插件”系统,用于全局性地控制Django 的输入或输出,可以理解为内置的app或者小框架。

django.core.handlers.base模块中定义了如何接入中间件,这也是学习Django源码的入口之一。

每个中间件组件负责实现一些特定的功能。例如,Django 包含一个中间件组件 AuthenticationMiddleware,它使用会话机制将用户与请求request关联起来。

中间件可以放在你的工程的任何地方,并以Python路径的方式进行访问。

Django 具有一些内置的中间件,并自动开启了其中的一部分,我们可以根据自己的需要进行调整。

一、如何启用中间件

若要启用中间件组件,请将其添加到 Django 配置文件settings.pyMIDDLEWARE 配置项列表中。

MIDDLEWARE 中,中间件由字符串表示。这个字符串以圆点分隔,指向中间件工厂的类或函数名的完整 Python 路径。下面是使用 django-admin startproject命令创建工程后,默认的中间件配置:

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',�]

实际上在Django中可以不使用任何中间件,如果你愿意的话,MIDDLEWARE 配置项可以为空。但是强烈建议至少使用 CommonMiddleware。而笔者的建议是保持默认的配置,这有助于你提高网站的安全性。

二、 中间件最关键的顺序问题

MIDDLEWARE 的顺序很重要,具有先后关系,因为有些中间件会依赖其他中间件。例如: AuthenticationMiddleware 需要在会话中间件中存储的经过身份验证的用户信息,因此它必须在 SessionMiddleware 后面运行 。

在请求阶段,调用视图之前,Django 按照定义的顺序执行中间件 MIDDLEWARE,自顶向下。

你可以把它想象成一个洋葱:每个中间件类都是一个“皮层”,它包裹起了洋葱的核心--实际业务视图。如果请求通过了洋葱的所有中间件层,一直到内核的视图,那么响应将在返回的过程中以相反的顺序再通过每个中间件层,最终返回给用户

如果某个层的执行过程认为当前的请求应该被拒绝,或者发生了某些错误,导致短路,直接返回了一个响应,那么剩下的中间件以及核心的视图函数都不会被执行。

三、Django内置的中间件

Django内置了下面这些中间件,满足了我们一般的需求:

Cache

缓存中间件

如果启用了该中间件,Django会以CACHE_MIDDLEWARE_SECONDS 配置的参数进行全站级别的缓存。

Common

通用中间件

该中间件为我们提供了一些便利的功能:

  • 禁止DISALLOWED_USER_AGENTS中的用户代理访问服务器

  • 自动为URL添加斜杠后缀和www前缀功能。如果配置项 APPEND_SLASHTrue ,并且访问的URL 没有斜杠后缀,在URLconf中没有匹配成功,将自动添加斜杠,然后再次匹配,如果匹配成功,就跳转到对应的url。 PREPEND_WWW 的功能类似。

  • 为非流式响应设置Content-Length头部信息。

作为展示的例子,这里额外贴出它的源代码,位于django.middleware.common模块中,比较简单,很容易读懂和理解:

class CommonMiddleware(MiddlewareMixin): “““ 去掉了doc “““ response_redirect_class = HttpResponsePermanentRedirect def process_request(self, request):  # Check for denied User-Agents  if 'HTTP_USER_AGENT' in request.META:for user_agent_regex in settings.DISALLOWED_USER_AGENTS: if user_agent_regex.search(request.META['HTTP_USER_AGENT']):  raise PermissionDenied('Forbidden user agent')  # Check for a redirect based on settings.PREPEND_WWW  host = request.get_host()  must_prepend = settings.PREPEND_WWW and host and not host.startswith('www.')  redirect_url = ('%s://www.%s' % (request.scheme, host)) if must_prepend else ''  # Check if a slash should be appended  if self.should_redirect_with_slash(request):path = self.get_full_path_with_slash(request)  else:path = request.get_full_path()  # Return a redirect if necessary  if redirect_url or path != request.get_full_path():redirect_url  = pathreturn self.response_redirect_class(redirect_url) def should_redirect_with_slash(self, request):  if settings.APPEND_SLASH and not request.path_info.endswith('/'):urlconf = getattr(request, 'urlconf', None)return ( not is_valid_path(request.path_info, urlconf) and is_valid_path('%s/' % request.path_info, urlconf))  return False def get_full_path_with_slash(self, request):  new_path = request.get_full_path(force_append_slash=True)  if settings.DEBUG and request.method in ('POST', 'PUT', 'PATCH'):raise RuntimeError( “You called this URL via %(method)s, but the URL doesn't end “ “in a slash and you have APPEND_SLASH set. Django can't “ “redirect to the slash URL while maintaining %(method)s data. “ “Change your form to point to %(url)s (note the trailing “ “slash), or set APPEND_SLASH=False in your Django settings.“ % {  'method': request.method,  'url': request.get_host()new_path, })  return new_path def process_response(self, request, response):  # If the given URL is “Not Found“, then check if we should redirect to  # a path with a slash appended.  if response.status_code == 404:if self.should_redirect_with_slash(request): return self.response_redirect_class(self.get_full_path_with_slash(request))  if settings.USE_ETAGS and self.needs_etag(response):warnings.warn( “The USE_ETAGS setting is deprecated in favor of “ “ConditionalGetMiddleware which sets the ETag regardless of “ “the setting. CommonMiddleware won't do ETag processing in “ “Django 2.1.“, RemovedInDjango21Warning)if not response.has_header('ETag'): set_response_etag(response)if response.has_header('ETag'): return get_conditional_response(  request,  etag=response['ETag'],  response=response, )  # Add the Content-Length header to non-streaming responses if not  # already set.  if not response.streaming and not response.has_header('Content-Length'):response['Content-Length'] = str(len(response.content))  return response def needs_etag(self, response):  “““Return True if an ETag header should be added to response.“““  cache_control_headers = cc_delim_re.split(response.get('Cache-Control', ''))  return all(header.lower() != 'no-store' for header in cache_control_headers)

GZip

内容压缩中间件

用于减小响应体积,降低带宽压力,提高传输速度。

该中间件必须位于其它所有需要读写响应体内容的中间件之前。

如果存在下面情况之一,将不会压缩响应内容:

  • 内容少于200 bytes

  • 已经设置了 Content-Encoding 头部属性

  • 请求的 Accept-Encoding 头部属性未包含 gzip.

可以使用 gzip_page()装饰器,为视图单独开启GZip压缩服务。

Conditional GET

有条件的GET访问中间件,很少使用。

Locale

本地化中间件

用于处理国际化和本地化,语言翻译。

Message

消息中间件

基于cookie或者会话的消息功能,比较常用。

Security

安全中间件

django.middleware.security.SecurityMiddleware中间件为我们提供了一系列的网站安全保护功能。主要包括下列所示,可以单独开启或关闭:

  • SECURE_BROWSER_XSS_FILTER

  • SECURE_CONTENT_TYPE_NOSNIFF

  • SECURE_HSTS_INCLUDE_SUBDOMAINS

  • SECURE_HSTS_PRELOAD

  • SECURE_HSTS_SECONDS

  • SECURE_REDIRECT_EXEMPT

  • SECURE_SSL_HOST

  • SECURE_SSL_REDIRECT

Session

会话中间件,非常常用。

Site

站点框架。

这是一个很有用,但又被忽视的功能。

它可以让你的Django具备多站点支持的功能。

通过增加一个site属性,区分当前re

源文地址:https://www.guoxiongfei.cn/cntech/24602.html