发布于 2015-08-24 15:52:45 | 656 次阅读 | 评论: 0 | 来源: 网络整理
本文讲述 Flask 0.7 版本的运行方式,与旧版本的运行方式基本相同,但也有一些细微的 差别。
建议你在阅读本文之前,先阅读 应用环境 。
假设有一个工具函数,这个函数返回用户重定向的 URL (包括 URL 的 next
参数、 或 HTTP 推荐 和索引页面):
from flask import request, url_for def redirect_url(): return request.args.get('next') or request.referrer or url_for('index')
如上例所示,这个函数访问了请求对象。如果你在一个普通的 Python 解释器中运行这个 函数,那么会看到如下异常:
>>> redirect_url() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'NoneType' object has no attribute 'request'
这是因为现在我们没有一个可以访问的请求。所以我们只能创建一个请求并绑定到当前 环境中。 test_request_context
方法可以创建一个 RequestContext
:
>>> ctx = app.test_request_context('/?next=http://example.com/')
这个环境有两种使用方法:一种是使用 with 语句;另一种是调用 push()
和 pop()
方法:
>>> ctx.push()
现在可以使用请求对象了:
>>> redirect_url() u'http://example.com/'
直到你调用 pop :
>>> ctx.pop()
可以把请求环境理解为一个堆栈,可以多次压入和弹出,可以方便地执行一个像内部 重定向之类的东西。
关于在 Python 解释器中使用请求环境的更多内容参见 在 Shell 中使用 Flask 。
如果深入 Flask WSGI 应用内部,那么会找到类似如下代码:
def wsgi_app(self, environ): with self.request_context(environ): try: response = self.full_dispatch_request() except Exception, e: response = self.make_response(self.handle_exception(e)) return response(environ, start_response)
request_context()
方法返回一个新的 RequestContext
对象,并且使用 with 语句把这个对象绑定 到环境。在 with 语句块中,在同一个线程中调用的所有东西可以访问全局请求 (flask.request
或其他)。
请求环境的工作方式就像一个堆栈,栈顶是当前活动请求。 push()
把环境压入堆栈中,而 pop()
把环境弹出。弹出的同时,会执行应用的 teardown_request()
函数。
另一件要注意的事情是:请求环境会在压入时自动创建一个 应用环境 。在此之前,应用没有应用环境。
如果在请求处理的过程中发生错误,那么 Flask 会如何处理呢?自 Flask 0.7 版本之后, 处理方式有所改变。这是为了更方便地反映到底发生了什么情况。新的处理方式非常简单:
before_request()
函数。如果 其中一个函数返回一个响应,那么其他函数将不再调用。但是在任何情况下,这个 返回值将会替代视图的返回值。before_request()
函数均没有响应,那么就会进行正常的 请求处理,匹配相应的视图,返回响应。after_request()
函数处理。在处理过程中,这个对象可能会被 替换或修改。teardown_request()
函数。这类 函数在任何情况下都会被执行,甚至是在发生未处理异常或请求预处理器没有执行( 例如在测试环境下,有时不想执行)的情况下。那么如果出错了会怎么样?在生产模式下,如果一个异常未被主要捕获处理,那么会调用 500 内部服务器处理器。在开发模式下,引发的异常不再被进一步处理,会提交给 WSGI 服务器。因此,需要使用交互调试器来查看调试信息。
Flask 0.7 版本的重大变化是内部服务器错误不再由请求后回调函数来处理,并且请求后 回调函数也不保证一定被执行。这样使得内部调试代码更整洁、更易懂和更容易定制。
同时还引入了新的卸载函数,这个函数在请求结束时一定会执行。
卸载回调函数的特殊之处在于其调用的时机是不固定的。严格地说,调用时机取决于 其绑定的 RequestContext
对象的生命周期。当请求环境弹出时就 会调用 teardown_request()
函数。
请求环境的生命周期是会变化的,当请求环境位于测试客户端中的 with 语句中或者在 命令行下使用请求环境时,其生命周期会被延长。因此知道生命周期是否被延长是很重要 的:
with app.test_client() as client: resp = client.get('/foo') # 到这里还没有调用卸载函数。即使这时响应已经结束,并且已经 # 获得响应对象,还是不会调用卸载函数。 # 只有到这里才会调用卸载函数。另外,如果另一个请求在客户端中被 # 激发,也会调用卸载函数。
在使用命令行时,可以清楚地看到运行方式:
>>> app = Flask(__name__) >>> @app.teardown_request ... def teardown_request(exception=None): ... print 'this runs after request' ... >>> ctx = app.test_request_context() >>> ctx.push() >>> ctx.pop() this runs after request >>>
记牢记:卸载函数在任何情况下都会被执行,甚至是在请求预处理回调函数没有执行, 但是发生异常的情况下。有的测试系统可能会临时创建一个请求环境,但是不执行 预处理器。请正确使用卸载处理器,确保它们不会执行失败。
部分 Flask 提供的对象是其他对象的代理。使用代理的原因是代理对象共享于不同的 线程,它们在后台根据需要把实际的对象分配给不同的线程。
多数情况下,你不需要关心这个。但是也有例外,在下列情况有下,知道对象是一个代理 对象是有好处的:
如果想要访问被代理的对象,可以使用 _get_current_object()
方法:
app = current_app._get_current_object() my_signal.send(app)
不管是否出错,在请求结束时,请求环境会被弹出,并且所有相关联的数据会被销毁。 但是在开发过程中,可能需要在出现异常时保留相关信息。在 Flask 0.6 版本及更早的 版本中,在发生异常时,请求环境不会被弹出,以便于交互调试器提供重要信息。
自 Flask 0.7 版本开始,可以通过设置 PRESERVE_CONTEXT_ON_EXCEPTION
配置变量 来更好地控制环境的保存。缺省情况下,这个配置变更与 DEBUG
变更关联。如果在 调试模式下,那么环境会被保留,而在生产模式下则不保留。
不要在生产环境下强制激活 PRESERVE_CONTEXT_ON_EXCEPTION
,因为这会在出现异常 时导致应用内存溢出。但是在调试模式下使用这个变更是十分有用的,你可以获得在生产 模式下出错时的环境。