使用 SocketIO 上传文件时,Flask request.stream.read() 正在停止

Posted

技术标签:

【中文标题】使用 SocketIO 上传文件时,Flask request.stream.read() 正在停止【英文标题】:Flask request.stream.read() is stopping when uploading file using SocketIO 【发布时间】:2020-12-20 16:30:32 【问题描述】:

我正在使用 flask-socketio 和 eventlet 运行 Flask 生产服务器,当尝试提交包含要上传的文件的表单时,Flask 无法读取整个请求。当文件超过几 kb(大约 50kb 或更多)时,就会发生这种情况。我要上传的文件是一个 60kb 的 .txt 文件,每行都有一个单词。文件大小为 1-2kb 的情况下,一切正常。

def get_file(request):
    if 'uploadFile' not in request.files:
        return redirect(request.url)
    return = request.file['uploadFile']

经过一些测试,我能够确定代码没有通过检查request.files。例如,我会尝试 print(request.files) 并且代码不会从那里继续前进,它只会挂起。

我知道 Flask 的内置方法可能不是最有效的,所以我找到了一个库 streaming-form-data 可以帮助加载大文件,因此将其实现为替代

def get_file(request):
    parser = StreamingFormDataParser(headers=request.headers)
    parser.register('file', FileTarget('/temp/file.txt')

    while True:
        chunk = request.stream.read(8192)
        if not chunk:
            break
        parser.data_received(chunk) # add read bytes to file
        socketio.sleep(1)

文件仍然无法完成上传,但是我发现它在尝试执行chunk = request.stream.read(8192) 时停止。这不会立即发生,它通常会在第 4-5 次迭代左右停止。在有和没有socketio.sleep() 的情况下进行了测试,据我所知,这对于需要更多时间的任务来说可能是必需的。

我使用 Flask Dev Server 进行了更多测试,发现如果我使用app.run(threaded=True),它将按预期完成并且代码将继续。但是我无法使用socketio.run() 和 eventlet 让它工作,例如我的main.py

import eventlet
eventlet.monkey_patch()

from app import app, socketio

if __name__ == "__main__":
    # app.run(threaded=True) # This will work and finish loading the file
    socketio.run(app) # does not work

while循环读取流期间我没有收到任何错误,只是没有继续获取下一个chunk = request.stream.read(8192)

【问题讨论】:

【参考方案1】:

找到了我需要的解决方案,结果发现它真的不是 Flask 的问题。在我的 POST 中,我只需要包含 chunking: true,它似乎从那里工作正常。

例如

$.ajax(
    type: 'POST',
    chunking: true,
    data: form_data,
    contentType: false,
);

作为测试,我恢复了我在上面所做的更改(尽管这些更改可能是为了更好)并确认它有效。

【讨论】:

以上是关于使用 SocketIO 上传文件时,Flask request.stream.read() 正在停止的主要内容,如果未能解决你的问题,请参考以下文章

使用 pytest 测试 flask-socketio 服务器发出的事件时出错

尽管使用了 socketio.run(),但“Flask-SocketIO 正在 Werkzeug 下运行”

Flask Docker 容器 SocketIO 问题

如何等待传递给 Flask-SocketIO 的 emit() 的回调?

在 beanstalk 上部署 flask-socketio

访问 flask-socketio 会话的问题