Python 发送文件前保持HTTP连接?

Python hold on the HTTP connection before sending files?

问题

这个问题困扰了我好久。我正在处理一个 web API,它提供了通过某些特定条件查询数据库、获取符合条件的数据并生成 .xls[=38= 的功能] 个文件供下载。

但是数据量真的很大,所以生成.xls文件会比较费时间。 这可能会导致 HTTP 超时。我曾经创建了一个生成器来逐行生成格式为 .csv 的记录。它在性能方面效果很好(我的意思是生成和下载速度快),但是有一些副作用。正如我在前两个问题中提到的:

问题

After a serious consideration, I finally decide to generate the whole .xls file on the server side, and then provide for download. But how can I maintain the http connection during the time for generating the .xls file?

"How can I maintain the http connection during the time for generating the .xls file?"

简单的回答:你不能。至少您不能保证单个简单的 HTTP GET 请求(和底层 TCP 连接)可靠地工作。根据客户端的具体情况和客户端所在的网络,您的用户可能经常遇到错误(您的应用程序无法处理的连接超时)。

所以,正确的问题是:无论生成文件需要多长时间以及他们的 Internet 连接有多糟糕,您需要哪种技术才能让用户获得此文件?

有很多种可能的方法,但它们都有各自的缺点。根据您要支持的浏览器,有几个选项。所有这些都需要客户端 JavaScript 使用。

您可能想使用现代的 Server-Sent events,它允许服务器主动触发浏览器中的事件,浏览器可以根据需要响应该事件。

更经典的方法是通过 HTTPS 进行(长)轮询,您可以像以前一样进行,但将客户端和服务器中的超时时间配置得相当长。此外,您需要设置 JavaScript 以防超时时重复请求。此外,还建立了防止超时的肮脏技术。

您可能需要使用术语 "server push"、"comet"、"long polling" 进行一些研究。这样做,您可能会阅读有关 WebSockets 的内容(在我看来您并不直接需要它)。

我想如果我是你,我现在会选择使用服务器发送的事件。但是你必须自己解决这个问题,具体取决于你的具体要求。

快速浏览一下,这篇文章的介绍可能是一个很好的阅读:https://jersey.java.net/documentation/latest/sse.html

另外,W3C Server-Sent Events specification的介绍也不错。引用:

Event streams requests can be redirected using HTTP 301 and 307 redirects as with normal HTTP requests. Clients will reconnect if the connection is closed; a client can be told to stop reconnecting using the HTTP 204 No Content response code.

Using this API rather than emulating it using XMLHttpRequest or an iframe allows the user agent to make better use of network resources in cases where the user agent implementor and the network operator are able to coordinate in advance. Amongst other benefits, this can result in significant savings in battery life on portable devices. This is discussed further in the section below on connectionless push.

我同意@Jan 的观点,服务器发送的事件 (SSE) 可能是可行的方法。如果你想更花哨,你可以设置一个 celery 任务队列并监听 task_complete 信号,然后通过 SSE 通知用户下载已准备就绪。这是 using SSE in Flask. And here is a link to celery and signaling

的示例

另一种方法是在初始请求中启动异步 Celery 任务,然后通过 setInterval() 客户端中的 ajax 请求继续检查任务是否完成。该路线只会检查 MyTask.AsyncResult(task_id).state