烧瓶结束响应并继续处理

发布于 2021-01-29 18:37:43

Flask中是否可以将响应发送给客户端,然后继续进行某些处理?我要完成一些簿记任务,但是我不想让客户等待。

请注意,这些实际上是我想做的非常快的事情,因此在这里实际上不适合创建新线程或使用队列。(这些快速的操作之一实际上是在作业队列中添加一些内容。)

关注者
0
被浏览
46
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    可悲的是,将响应返回给客户端后,拆卸回调不执行:

    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
    

    这是此处提供的先前答案的摘要。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看