当前位置:K88软件开发文章中心网站服务器框架django → 文章内容

Django 中间件

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-25 14:19:28

由 lxjazni_7 创建,路飞 最后一次修改 2016-02-24 在有些场合,需要对Django处理的每个request都执行某段代码。 这类代码可能是在view处理之前修改传入的request,或者记录日志信息以便于调试,等等。这类功能可以用Django的中间件框架来实现,该框架由切入到Django的request/response处理过程中的钩子集合组成。 这个轻量级低层次的plug-in系统,能用于全面的修改Django的输入和输出。每个中间件组件都用于某个特定的功能。 如果你是顺着这本书读下来的话,你应该已经多次见到“中间件”了第12章中所有的session和user工具都籍由一小簇中间件实现(例如,由中间件设定view中可见的request.session 和 request.user )。第13章讨论的站点范围cache实际上也是由一个中间件实现,一旦该中间件发现与view相应的response已在缓存中,就不再调用对应的view函数。第14章所介绍的 flatpages , redirects , 和 csrf 等应用也都是通过中间件组件来完成其魔法般的功能。这一章将深入到中间件及其工作机制中,并阐述如何自行编写中间件。什么是中间件我们从一个简单的例子开始。高流量的站点通常需要将Django部署在负载平衡proxy(参见第20章)之后。 这种方式将带来一些复杂性,其一就是每个request中的远程IP地址(request.META["REMOTE_IP"])将指向该负载平衡proxy,而不是发起这个request的实际IP。 负载平衡proxy处理这个问题的方法在特殊的 X-Forwarded-For 中设置实际发起请求的IP。因此,需要一个小小的中间件来确保运行在proxy之后的站点也能够在request.META["REMOTE_ADDR"] 中得到正确的IP地址:class SetRemoteAddrFromForwardedFor(object): def process_request(self, request): try: real_ip = request.META['HTTP_X_FORWARDED_FOR'] except KeyError: pass else: # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. # Take just the first one. real_ip = real_ip.split(",")[0] request.META['REMOTE_ADDR'] = real_ip(Note: Although the HTTP header is called X-Forwarded-For , Django makes it available asrequest.META['HTTP_X_FORWARDEDFOR'] . With the exception of content-length and content-type , any HTTP headers in the request are converted to request.META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP prefix to the name.)一旦安装了该中间件(参见下一节),每个request中的 X-Forwarded-For 值都会被自动插入到request.META['REMOTE_ADDR'] 中。这样,Django应用就不需要关心自己是否位于负载平衡proxy之后;简单读取 request.META['REMOTE_ADDR'] 的方式在是否有proxy的情形下都将正常工作。实际上,为针对这个非常常见的情形,Django已将该中间件内置。 它位于 django.middleware.http 中, 下一节将给出这个中间件相关的更多细节。安装中间件如果按顺序阅读本书,应当已经看到涉及到中间件安装的多个示例,因为前面章节的许多例子都需要某些特定的中间件。 出于完整性考虑,下面介绍如何安装中间件。要启用一个中间件,只需将其添加到配置模块的 MIDDLEWARE_CLASSES 元组中。 在 MIDDLEWARE_CLASSES 中,中间件组件用字符串表示: 指向中间件类名的完整Python路径。 例如,下面是 django-admin.py startproject创建的缺省 MIDDLEWARE_CLASSES :MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',)Django项目的安装并不强制要求任何中间件,如果你愿意, MIDDLEWARE_CLASSES 可以为空。这里中间件出现的顺序非常重要。 在request和view的处理阶段,Django按照 MIDDLEWARE_CLASSES 中出现的顺序来应用中间件,而在response和异常处理阶段,Django则按逆序来调用它们。 也就是说,Django将MIDDLEWARE_CLASSES 视为view函数外层的顺序包装子: 在request阶段按顺序从上到下穿过,而在response则反过来。中间件方法现在,我们已经知道什么是中间件和怎么安装它,下面将介绍中间件类中可以定义的所有方法。Initializer: init(self) init(self)「初始化]在中间件类中, init() 方法用于执行系统范围的设置。出于性能的考虑,每个已启用的中间件在每个服务器进程中只初始化 一 次。 也就是说 init() 仅在服务进程启动的时候调用,而在针对单个request处理时并不执行。对一个middleware而言,定义 init() 方法的通常原因是检查自身的必要性。 如果 init() 抛出异常django.core.exceptions.MiddlewareNotUsed ,则Django将从middleware栈中移出该middleware。 可以用这个机制来检查middleware依赖的软件是否存在、服务是否运行于调试模式、以及任何其它环境因素。在中间件中定义 init() 方法时,除了标准的 self 参数之外,不应定义任何其它参数。Request预处理函数: process_request(self, request) process_request(self, request)这个方法的调用时机在Django接收到request之后,但仍未解析URL以确定应当运行的view之前。 Django向它传入相应的 HttpRequest 对象,以便在方法中修改。process_request() 应当返回 None 或 HttpResponse 对象.如果返回 None , Django将继续处理这个request,执行后续的中间件, 然后调用相应的view.如果返回 HttpResponse 对象, Django 将不再执行 任何 其它的中间件(而无视其种类)以及相应的view。 Django将立即返回该 HttpResponse .View预处理函数: process_view(self, request, view, args, kwargs) process_view(self, request, view, args, kwargs)这个方法的调用时机在Django执行完request预处理函数并确定待执行的view之后,但在view函数实际执行之前。表15-1列出了传入到这个View预处理函数的参数。表 15-1. 传入process_view()的参数参数说明requestThe HttpRequest object.viewThe Python function that Django will call to handle this request. This is the actual function object itself, not the name of the function as a strin

[1] [2] [3]  下一页


Django 中间件