繁体   English   中英

uwsgi:发送 http 响应并继续执行

[英]uwsgi: Send http response and continue execution

来自 uwsgi 文档:

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]

是否可以响应 http 请求(关闭 http 连接)并继续执行流程(不使用任何线程/队列/外部服务等)? 像这样:

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    end_response(b"Hello World")
    #HTTP connection is closed
    #continue execution..

不幸的是,您在返回响应后无法继续执行代码。 如果使用多线程,会容易得多,但如果不使用多线程,则可以通过在HTML响应中添加AJAX调用来解决该问题,该调用将向服务器额外路由之一发送POST请求,该路由的处理函数将是您想要的执行代码返回响应后。 这是使用Flask的一种可能的方法:

myflaskapp.py

from flask import Flask, render_template_string
import time

app = Flask(__name__)

@app.route('/run', methods=['POST'])
def run():
    # this is where you put your "continue execution..." code
    # below code is used to test if it runs after HTTP connection close
    time.sleep(8)
    print('Do something')
    return ''

@app.route('/')
def index():
    return render_template_string('''
            Hello World!
            <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
            <script>
            $(function() {
                $.ajax({
                    type: "POST",
                    url: "{{ url_for('run') }}"
                });
            })
            </script>
            ''')

if __name__ == "__main__":
    app.run(host='0.0.0.0')

您可以使用以下命令在端口9091上运行服务器:

uwsgi --http 127.0.0.1:9091 --wsgi-file myflaskapp.py --callable app

要测试它是否正常工作,可以转到地址localhost:9091 如果一切正常,您应该看到页面立即被加载,而终端仅打印输出Do something经过8 seconds have passedDo something ,表明该函数run在HTTP连接关闭后执行。

TL;DR - 如果您使用的是 Django,您可以跳到答案的末尾。

是的,有办法做到这一点。 您可以连接到application可调用返回的 object 的.close()方法(或者,通过 env 返回的wsgi.file_wrapper

检查 PEP333,特别是服务器端规范部分: https://peps.python.org/pep-0333/#the-server-gateway-side

    result = application(environ, start_response)
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        if hasattr(result, 'close'):
            result.close()

如您所见, result.close()将在最后被调用,此时数据已经发送。

当然,这只是一些参考代码,它不处理上游和在继续执行之前终止连接。 但是表现良好的 wsgi 服务器,例如uwsgi和(大概) gunicorn ,可以。 他们将通过关闭套接字(或上游协议要求的任何内容)向上游发出请求已完成发送的信号,然后调用.close()

如果你使用的是 Django,你已经设置好了,因为它有request_finished信号。 这是它的工作原理,它与.close()挂钩,如上所述:

https://github.com/django/django/blob/57c7220280db19dc9dda0910b90cf1ceac50c66f/django/http/response.py#L323

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM