烧瓶结束响应并继续处理
Flask中是否可以将响应发送给客户端,然后继续进行某些处理?我要完成一些簿记任务,但是我不想让客户等待。
请注意,这些实际上是我想做的非常快的事情,因此在这里实际上不适合创建新线程或使用队列。(这些快速的操作之一实际上是在作业队列中添加一些内容。)
-
可悲的是,将响应返回给客户端后,拆卸回调不执行:
import flask import time app = flask.Flask("after_response") @app.teardown_request def teardown(request): time.sleep(2) print("teardown_request") @app.route("/") def home(): return "Success!\n" if __name__ == "__main__": app.run()
卷曲时,您会注意到在显示响应之前有2s的延迟,而不是卷曲立即结束,然后在2s之后记录。日志进一步确认了这一点:
teardown_request 127.0.0.1 - - [25/Jun/2018 15:41:51] "GET / HTTP/1.1" 200 -
返回响应后执行的正确方法是使用WSGI中间件,该中间件向响应迭代器的close方法添加了一个钩子。这不像
teardown_request
装饰器那么简单,但是仍然很简单:import traceback from werkzeug.wsgi import ClosingIterator class AfterResponse: def __init__(self, app=None): self.callbacks = [] if app: self.init_app(app) def __call__(self, callback): self.callbacks.append(callback) return callback def init_app(self, app): # install extension app.after_response = self # install middleware app.wsgi_app = AfterResponseMiddleware(app.wsgi_app, self) def flush(self): for fn in self.callbacks: try: fn() except Exception: traceback.print_exc() class AfterResponseMiddleware: def __init__(self, application, after_response_ext): self.application = application self.after_response_ext = after_response_ext def __call__(self, environ, start_response): iterator = self.application(environ, start_response) try: return ClosingIterator(iterator, [self.after_response_ext.flush]) except Exception: traceback.print_exc() return iterator
然后可以这样使用:
@app.after_response def after(): time.sleep(2) print("after_response")
从外壳程序中,您将看到响应立即返回,然后2秒钟后
after_response
它将返回日志:127.0.0.1 - - [25/Jun/2018 15:41:51] "GET / HTTP/1.1" 200 - after_response
这是此处提供的先前答案的摘要。