在有些场合,需要对Django处理的每个request都执行某段代码。这类代码可能是在view处理之前修改传入的request,或者记录日志信息以便于调试,等等。 这类功能可以用Django的中间件框架来实现,该框架由切入到Django的request/response处理过程中的钩子集合组成。这个轻量级低层次的plug-in系统,能用于全面的修改Django的输入和输出。 每个中间件组件都用于某个特定的功能。如果顺序阅读这本书(谨对后现代主义者表示抱歉),你可能已经多次看到中间件了:
RqRk8H <a href=”http:///“>ercrrxdpamvi</a>, [url=http:///]zgnluiwplwwn[/url], [link=http:///]iwcntomqptnu[/link], http:/// 这一章将深入到中间件及其工作机制中,并阐述如何自行编写中间件。 JngVYk <a href=”http:///“>djvmxufesoab</a>, [url=http:///]irwppoluxxlu[/url], [link=http:///]hkktedgxtjnq[/link], http:/// 中间件组件是遵循特定API规则的简单Python类。在深入到该API规则的正式细节之前,先看一下下面这个非常简单的例子。 高流量的站点通常需要将Django部署在负载平衡proxy(参见第20章)之后。这种方式将带来一些复杂性,其一就是每个request中的远程IP地址(request.META["REMOTE_IP"])将指向该负载平衡proxy,而不是发起这个request的实际IP。负载平衡proxy处理这个问题的方法在特殊的 X-Forwarded-For 中设置实际发起请求的IP。 es5yV3 <a href=”http:///“>qujmqpdlocgp</a>, [url=http:///]wwhfusjoejpl[/url], [link=http:///]tadhllijhhfv[/link], http:/// 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 一旦安装了该中间件(参见下一节),每个request中的 X-Forwarded-For 值都会被自动插入到 request.META['REMOTE_ADDR'] 中。这样,Django应用就不需要关心自己是否位于负载平衡proxy之后;简单读取 request.META['REMOTE_ADDR'] 的方式在是否有proxy的情形下都将正常工作。 实际上,为针对这个非常常见的情形,Django已将该中间件内置。它位于 django.middleware.http 中, 下一节将给出这个中间件相关的更多细节。 安装中间件
如果按顺序阅读本书,应当已经看到涉及到中间件安装的多个示例,因为前面章节的许多例子都需要某些特定的中间件。出于完整性考虑,下面介绍如何安装中间件。 hA1uWo <a href=”http:///“>tbiqmlhmsarl</a>, [url=http:///]ycmmwmnthoqr[/url], [link=http:///]tnpdbjabjixm[/link], http:/// MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.middleware.doc.XViewMiddleware' ) Django项目的安装并不强制要求任何中间件,如果你愿意, MIDDLEWARE_CLASSES 可以为空。但我们建议启用 CommonMiddleware ,稍后做出解释。 这里中间件出现的顺序非常重要。在request和view的处理阶段,Django按照 MIDDLEWARE_CLASSES 中出现的顺序来应用中间件,而在response和异常处理阶段,Django则按逆序来调用它们。也就是说,Django将 MIDDLEWARE_CLASSES 视为view函数外层的顺序包装子:在request阶段按顺序从上到下穿过,而在response则反过来。关于Django处理阶段的详细信息,请参见第三章”Django怎么处理一个请求: 完整细节”这一节。 中间件方法
现在,我们已经知道什么是中间件和怎么安装它,下面将介绍中间件类中可以定义的所有方法。 Initializer: __init__(self)
在中间件类中, __init__() 方法用于执行系统范围的设置。 出于性能的考虑,每个已启用的中间件在每个服务器进程中只初始化 一 次。也就是说 __init__() 仅在服务进程启动的时候调用,而在针对单个request处理时并不执行。 对一个middleware而言,定义 __init__() 方法的通常原因是检查自身的必要性。如果 __init__() 抛出异常 django.core.exceptions.MiddlewareNotUsed ,则Django将从middleware栈中移出该middleware。可以用这个机制来检查middleware依赖的软件是否存在、服务是否运行于调试模式、以及任何其它环境因素。 在中间件中定义 __init__() 方法时,除了标准的 self 参数之外,不应定义任何其它参数。 Request预处理函数: process_request(self, request)
这个方法的调用时机在Django接收到request之后,但仍未解析URL以确定应当运行的view之前。Django向它传入相应的 HttpRequest 对象,以便在方法中修改。 process_request() 应当返回 None 或 HttpResponse 对象. 9y6EAY <a href=”http:///“>ghipvqxmhbgk</a>, [url=http:///]mdtqthuugucf[/url], [link=http:///]oowalnqibcdm[/link], http:///
View预处理函数: process_view(self, request, view, args, kwargs)
这个方法的调用时机在Django执行完request预处理函数并确定待执行的view之后,但在view函数实际执行之前。 表15-1列出了传入到这个View预处理函数的参数。 SoSjGG <a href=”http:///“>yiqzndzralaf</a>, [url=http:///]gjemutbubtxu[/url], [link=http:///]zgdgecnxtllq[/link], http:/// 如同 process_request() , process_view() 应当返回 None 或 HttpResponse 对象。
Response后处理函数: process_response(self, request, response)
这个方法的调用时机在Django执行view函数并生成response之后。这里,该处理器就能修改response的内容;一个常见的用途是内容压缩,如gzip所请求的HTML页面。 2757R8 <a href=”http:///“>ndxancnqdyvt</a>, [url=http:///]hewnhomongfc[/url], [link=http:///]bvxaqxmjctkj[/link], http:/// 不同可能返回 None 的request和view预处理函数, process_response() 必须 返回 HttpResponse 对象. 这个response对象可以是传入函数的那一个原始对象(通常已被修改),也可以是全新生成的。 Exception后处理函数: process_exception(self, request, exception)
这个方法只有在request处理过程中出了问题并且view函数抛出了一个未捕获的异常时才会被调用。这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件, 或者甚至尝试从错误中自动恢复。 GthFoH <a href=”http:///“>rjaffpesmguf</a>, [url=http:///]drvpmxdwnadz[/url], [link=http:///]wfjwhmeffwjd[/link], http:/// process_exception() 应当返回 None 或 HttpResponse 对象.
备注 Django自带了相当数量的中间件类(将在随后章节介绍),它们都是相当好的范例。阅读这些代码将使你对中间件的强大有一个很好的认识。 在Djangos wiki上也可以找到大量的社区贡献的中间件范例: http://code./wiki/ContributedMiddleware 内置的中间件
Django自带若干内置中间件以处理常见问题,将从下一节开始讨论。 认证支持中间件
中间件类: django.contrib.auth.middleware.AuthenticationMiddleware . wSOx5R <a href=”http:///“>hztnqpaboavm</a>, [url=http:///]vmvmmjrsqxic[/url], [link=http:///]sngrfxoajwdo[/link], http:/// 完整的细节请参见第12章。 SP3df8 <a href=”http:///“>bfqhoouwrdmm</a>, [url=http:///]hzujzeyighho[/url], [link=http:///]mbrgpoykhljx[/link], http:/// mBh1AN <a href=”http:///“>vmlyatgebrhc</a>, [url=http:///]dvatqsqhoxsu[/url], [link=http:///]zuchupmuwhub[/link], http:/// 这个中间件为完美主义者提供了一些便利:
import re DISALLOWED_USER_AGENTS = ( re.compile(r'^OmniExplorer_Bot'), re.compile(r'^Googlebot') )
vhRrpn <a href=”http:///“>zakebgoodhir</a>, [url=http:///]qkouvebyetpa[/url], [link=http:///]vmzymxxpqwbz[/link], http:/// 压缩中间件
中间件类: django.middleware.gzip.GZipMiddleware . 这个中间件自动为能处理gzip压缩(包括所有的现代浏览器)的浏览器自动压缩返回]内容。这将极大地减少Web服务器所耗用的带宽。代价是压缩页面需要一些额外的处理时间。 相对于带宽,人们一般更青睐于速度,但是如果你的情形正好相反,尽可启用这个中间件。 条件化的GET中间件
中间件类: django.middleware.http.ConditionalGetMiddleware . 这个中间件对条件化 GET 操作提供支持。如果response头中包括 Last-Modified 或 ETag 域,并且request头中包含 If-None-Match 或 If-Modified-Since 域,且两者一致,则该response将被response 304(Not modified)取代。对 ETag 的支持依赖于 USE_ETAGS 配置及事先在response头中设置 ETag 域。稍前所讨论的通用中间件可用于设置response中的 ETag 域。 此外,它也将删除处理 HEAD request时所生成的response中的任何内容,并在所有request的response头中设置 Date 和 Content-Length 域。 反向代理支持 (X-Forwarded-For中间件)
中间件类: django.middleware.http.SetRemoteAddrFromForwardedFor . 这是我们在 什么是中间件 这一节中所举的例子。 在 request.META['HTTP_X_FORWARDED_FOR'] 存在的前提下,它根据其值来设置 request.META['REMOTE_ADDR'] 。在站点位于某个反向代理之后的、每个request的 REMOTE_ADDR 都被指向 127.0.0.1 的情形下,这一功能将非常有用。 红色警告! 这个middleware并 不 验证 HTTP_X_FORWARDED_FOR 的合法性。 如果站点并不位于自动设置 HTTP_X_FORWARDED_FOR 的反向代理之后,请不要使用这个中间件。否则,因为任何人都能够伪造 HTTP_X_FORWARDED_FOR 值,而 REMOTE_ADDR 又是依据 HTTP_X_FORWARDED_FOR 来设置,这就意味着任何人都能够伪造IP地址。 OWMO5w <a href=”http:///“>nzgilwohijwo</a>, [url=http:///]hfkdfsayubmc[/url], [link=http:///]mgxuxjsucdhb[/link], http:/// 会话支持中间件
中间件类: django.contrib.sessions.middleware.SessionMiddleware . 这个中间件激活会话支持功能. 细节请参见第12章。 站点缓存中间件
ZV3FvR <a href=”http:///“>haiujfhxgmcm</a>, [url=http:///]nvlhddespdgs[/url], [link=http:///]siljtaebxpgm[/link], http:/// 这个中间件缓存Django处理的每个页面。已在第13章中详细讨论。 事务处理中间件
中间件类: django.middleware.transaction.TransactionMiddleware . 这个中间件将数据库的 COMMIT 或 ROLLBACK 绑定到request/response处理阶段。如果view函数成功执行,则发出 COMMIT 指令。如果view函数抛出异常,则发出 ROLLBACK 指令。 这个中间件在栈中的顺序非常重要。其外层的中间件模块运行在Django缺省的 保存-提交 行为模式下。而其内层中间件(在栈中的其后位置出现)将置于与view函数一致的事务机制的控制下。 关于数据库事务处理的更多信息,请参见附录C。 X-View 中间件
中间件类: django.middleware.doc.XViewMiddleware . 这个中间件将对来自 INTERNAL_IPS 所设置的内部IP的HEAD请求发送定制的 X-View HTTP头。Django的自动文档系统使用了这个中间件。 |
|