Django中间件

栏目: Python · 发布时间: 7年前

内容简介:Django中间件

中间件是面向切面编程的好例子,它是一个可以介入Django的request和response处理过程的钩子框架,一个轻量级、底层的“插件”系统,用于在全局修改Django的输入或输出。

要使用中间件,首先要在settings中设置:

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项目的默认设置,每一项字符串都代表一个中间件。中间件就像洋葱一样,每个中间件都是一个层,在用户请求阶段,调用定义的view函数之前,请求以自上而下的顺序通过所有的层,view函数处理之后,响应以自下而上的顺序通过所有的层,期间经过的每个中间件都会对请求或者响应进行处理。

自定义中间件

要自定义中间件,写一个类即可:

class SimpleMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

__init__初始化方法只在web服务启动时调用一次,get_response参数是必需的,这个参数指的是下一个中间件或者view函数(如果是最后一个中间件)。

每个请求都会调用一次__call__,先对请求做处理,然后将请求发往下一个中间件(get_response),一层层的迭代,就像栈一样,返回时对响应做处理。

如果其中一个层的中间件决定短路并返回响应而不调用其get_response,那么该层下面的层都不会看到请求或响应,只有该中间件和之上的中间件才会看到响应。

短路可以起到一些ip过滤之类的效果:

class IpFilterMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        if request.META.has_key('HTTP_X_FORWARDED_FOR'):
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:  
            ip = request.META['REMOTE_ADDR']
        if ip == '127.0.0.1':
            return HttpResponse('You are forbidden')
        response = self.get_response(request)
        return response

设置:

MIDDLEWARE = [
    'path.to.IpFilterMiddleware',

上述中间件把当地访问拦截了,实际应用中可以为ip建立黑名单,然后检查访问ip是否在黑名单中。

我们也可以将中间件标记为未使用,只要在__init__中引发一个django.core.exceptions.MiddlewareNotUsed异常即可。

其它的中间件钩子

除了前面描述的基本请求/响应中间件模式,您还可以向基于类的中间件添加三种其他特殊方法:

process_view (request, view_func, view_args, view_kwargs)

在调用view之前被调用。

它应该返回一个None 或一个HttpResponse对象。 如果返回None,Django 将会继续处理这个请求,执行其它的process_view() 中间件,然后调用对应的视图。 如果它返回一个HttpResponse对象,也会起到短路作用。

process_exception (request, exception)

当一个view引发异常时,Django会调用process_exception()来处理。返回一个None或一个HttpResponse对象。如果返回HttpResponse对象,会将响应交给处理响应的中间件处理。由于处理响应时是从下到上的,此层以上的process_exception()是不会被调用的。

process_template_response (request, response)

response参数应该是一个由view或者中间件返回的TemplateResponse对像(或等价的对象)。

如果响应的实例有render()方法,process_template_response()会在view刚好执行完毕之后被调用。 这个方法必须返回一个实现了render方法的响应对象。 

开发阶段通常将DEBUG打开以调试错误,部署时会关闭DEBUG以免用户看到错误信息。我们可以写一个异常中间件,让有权限的管理员可以在DEBUG关闭的情况下看到错误信息,这样就避免了切换的麻烦;

import sys

from django.views.debug import technical_500_response

class ExceptionMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

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

    def process_exception(self, request, exception):
        if request.user.is_admin:
            return technical_500_response(request, *sys.exc_info())

置于中间件的最底层,这样管理员可以看到用户无法看到的错误详细信息。

关于异常处理

Django会自动将视图或中间件引发的异常转换为具有错误状态代码的适当HTTP响应,这种转换发生在每个中间件之前和之后,我们是无需使用try捕捉异常的。

与旧版本中间件的兼容

在Django 1.10版本之前,中间件设置名为MIDDLEWARE_CLASSES,是长这样的:

class SessionMiddleware(object):
    def __init__(self):
        engine = import_module(settings.SESSION_ENGINE)
        self.SessionStore = engine.SessionStore

    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)

    def process_response(self, request, response):
        ...

Django提供django.utils.deprecation.MiddlewareMixin以简化与MIDDLEWARE和旧的MIDDLEWARE_CLASSES兼容的中间件类。 Django中包含的所有中间件类都兼容这两种设置。

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

新版继承自MiddlewareMixin的SessionMiddleware:

class SessionMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
        self.get_response = get_response
        engine = import_module(settings.SESSION_ENGINE)
        self.SessionStore = engine.SessionStore

    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)

    def process_response(self, request, response):
        ...

混合类提供一个__init__()方法,它接受一个可选的get_response参数,并将其存储在self.get_response中。

__call__()方法:

  • 调用self.process_request(request)(已定义的话)。
  • 调用self.get_response(request)获取后续中间件或者视图的响应。
  • 调用self.process_response(request, response)(已定义的话)。
  • 返回响应。

在大多数情况下,继承这种混合类足以使旧式中间件与新系统兼容,具有足够的向后兼容性。

上述的异常中间件也可以写为:

from django.utils.deprecation import MiddlewareMixin

class ExceptionMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        if request.user.is_admin:
            return technical_500_response(request, *sys.exc_info())

使用MIDDLEWARE和MIDDLEWARE_CLASSES之间的行为差​​异:

  • 在MIDDLEWARE_CLASSES下,即使上层中间件的process_request方法短路,下层的中间件也会调用它的process_response方法。 在MIDDLEWARE下, 如果中间件发生短路,则只有中间件和之上的中间件才会看到响应。
  • 在MIDDLEWARE_CLASSES下,process_exception适用于从中间件process_request方法引发的异常。 在MIDDLEWARE下,process_exception仅适用于view或者TemplateResponse的render方法引发的异常 。 从中间件引发的异常转换为适当的HTTP响应,然后传递给下一个中间件。
  • 在MIDDLEWARE_CLASSES下,如果process_response方法引发异常,则会跳过所有较早中间件的process_response方法然后返回500错误,而在MIDDLEWARE下,从中间件引发的异常将立即转换为适当的HTTP响应,然后下一个中间件将会看到该响应。 由于中间件引发异常,中间件不会被跳过。

处理流式响应

StreamingHttpResponse并没有content属性,使用时必须加以判断:

if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)

用生成器处理过大的内容:

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)

以上所述就是小编给大家介绍的《Django中间件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python Machine Learning

Python Machine Learning

Sebastian Raschka / Packt Publishing - ebooks Account / 2015-9 / USD 44.99

About This Book Leverage Python' s most powerful open-source libraries for deep learning, data wrangling, and data visualization Learn effective strategies and best practices to improve and opti......一起来看看 《Python Machine Learning》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具