当前位置: 首页 > 知识库问答 >
问题:

无法上传大文件到Python瓶在GCP应用程序引擎

景德海
2023-03-14

更新:(2020年5月18日)本帖末尾的解决方案!

我正在尝试将大型CSV文件(30MB-2GB)从浏览器上载到运行Python3.7Flask的GCP应用程序引擎,然后将这些文件推送到GCP存储。这在大型文件的本地测试中效果很好,但如果文件大小超过20MB,则在GCP上会立即出现错误,出现“413-您的客户端发出了太大的请求”。这个错误在上传时立即发生,甚至在它到达我的自定义Python逻辑之前(我怀疑应用程序引擎正在检查内容长度标题)。在进行了大量的SO/博客研究之后,我尝试了许多解决方案,但都无济于事。请注意,我使用的是运行Gunicorn服务器的F1实例的基本/免费应用程序引擎设置。

首先,我尝试设置应用程序。config['MAX_CONTENT_LENGTH']=2147483648但这并没有改变任何东西(所以发布)。我的应用程序在到达Python代码之前仍然抛出错误:

# main.py
    app.config['MAX_CONTENT_LENGTH'] = 2147483648   # 2GB limit

    @app.route('/', methods=['POST', 'GET'])
    def upload():
        # COULDN'T GET THIS FAR WITH A LARGE UPLOAD!!!
        if flask.request.method == 'POST':

            uploaded_file = flask.request.files.get('file')

            storage_client = storage.Client()
            storage_bucket = storage_client.get_bucket('my_uploads')

            blob = storage_bucket.blob(uploaded_file.filename)
            blob.upload_from_string(uploaded_file.read())

<!-- index.html -->
    <form method="POST" action='/upload' enctype="multipart/form-data">
        <input type="file" name="file">
    </form>

经过进一步的研究,我切换到使用Flask-Dropzone的分块上传,希望我可以批量上传数据,然后将CSV文件追加/构建为存储Blob:

# main.py
app = flask.Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 2147483648   # 2GB limit
dropzone = Dropzone(app)


@app.route('/', methods=['POST', 'GET'])
def upload():

    if flask.request.method == 'POST':

        uploaded_file = flask.request.files.get('file')

        storage_client = storage.Client()
        storage_bucket = storage_client.get_bucket('my_uploads')

        CHUNK_SIZE = 10485760  # 10MB
        blob = storage_bucket.blob(uploaded_file.filename, chunk_size=self.CHUNK_SIZE)

        # hoping for a create-if-not-exists then append thereafter
        blob.upload_from_string(uploaded_file.read())

JS/超文本标记语言直接来自我在网上找到的几个样本:

    <script>
       Dropzone.options.myDropzone = {
       timeout: 300000,
       chunking: true,
       chunkSize: 10485760 };
    </script>
    ....
    <form method="POST" action='/upload' class="dropzone dz-clickable" 
      id="dropper" enctype="multipart/form-data">
    </form>

上面的内容是分块上传的(我可以看到对POST/upload的重复调用),但是对blob的调用。从\u字符串上载(上载的\u file.read())只需将blob内容替换为上载的最后一个块,而不是追加。即使我去掉chunk\u size=self,这也不起作用。块大小参数。

接下来,我研究了如何写入/tmp,然后是如何写入存储,但文档说写入/tmp占用了我仅有的少量内存,而其他地方的文件系统是只读的,因此这两种方式都不起作用。

是否有附加API或经批准的方法将大文件上载到GCP应用程序引擎并推送/流式存储?鉴于代码在我的本地服务器上运行(并且很高兴地上传到GCP存储),我假设这是应用程序引擎中的一个内置限制,需要解决。

解决方案(5/18/2020)我能够使用Flask-Dropzone让JavaScript将上载分割成许多10MB块,并一次将这些块发送到Python服务器。在Python方面,我们会继续 /tmp附加到文件中,以“构建”内容,直到所有块都进来。最后,在最后一块,我们将上传到GCP存储,然后删除 /tmp文件。

@app.route('/upload', methods=['POST'])
def upload():

    uploaded_file = flask.request.files.get('file')

    tmp_file_path = '/tmp/' + uploaded_file.filename
    with open(tmp_file_path, 'a') as f:
        f.write(uploaded_file.read().decode("UTF8"))

    chunk_index = int(flask.request.form.get('dzchunkindex')) if (flask.request.form.get('dzchunkindex') is not None)  else 0
    chunk_count = int(flask.request.form.get('dztotalchunkcount')) if (flask.request.form.get('dztotalchunkcount') is not None)  else 1

    if (chunk_index == (chunk_count - 1)):
        print('Saving file to storage')
        storage_bucket = storage_client.get_bucket('prairi_uploads')
        blob = storage_bucket.blob(uploaded_file.filename) #CHUNK??

        blob.upload_from_filename(tmp_file_path, client=storage_client)
        print('Saved to Storage')

        print('Deleting temp file')
        os.remove(tmp_file_path)
<!-- index.html -->
        <script>
          Dropzone.options.myDropzone = {
          ... // configs
          timeout: 300000,
          chunking: true,
          chunkSize: 1000000
        };
        </script>

请注意/tmp与RAM共享资源,因此您需要的RAM至少与上载的文件大小相同,而且Python本身需要更多(我必须使用一个F4实例)。我想有更好的解决方案来写块存储,而不是/tmp,但我还没有做到这一点。

共有1个答案

淳于功
2023-03-14

答案是不能在单个HTTP请求中上传或下载大于32 MB的文件。来源

您需要重新设计服务以在多个HTTP请求中传输数据,使用预签名URL直接将数据传输到云存储,或者选择不使用全局前端(GFE)的不同服务,如计算引擎。这不包括云功能、云运行、应用引擎灵活等服务。

如果使用多个HTTP请求,则需要管理内存,因为所有临时文件都存储在内存中。这意味着在接近2 GB的最大实例大小时会出现问题。

 类似资料:
  • html代码 用于遍历文件列表并一次上载一个文件列表的上载逻辑 一次上载一个文件的Servicecall逻辑 2020-09-21 00:38:24.114错误11348---[nio-5200-exec-5]O.a.C.C.C.[.[.[/].[dispatcherServlet]:路径为[]的上下文中servlet[dispatcherServlet]的servlet.Service()引发异

  • 我正在appengine虚拟机上开发一个Flask应用程序。我想上传文件到谷歌云存储,所以我使用连接到云存储。仅在VM中测试时,我的应用程序运行正常,没有错误。但是,在我使用部署并在部署的应用程序上测试上载功能后,它失败并返回错误。日志显示了回溯,这是由于连接到云存储的代码行: 具体错误是

  • 我试图上传一个图像约1.62MB到终端写使用flask.request.files对象总是空的。我检查了以下问题,但没有运气: 烧瓶request.files是空的 https://github.com/requests/requests/issues/2505 如何在烧瓶中使用ajax调用上传文件 这是我的服务器: 我的客户: 在我看来,一切都很干净,我不知道哪里出了问题。请求对象中的“文件”属

  • 我试图设置NGINX,uWSGI和烧瓶。我目前正在得到, uWSGI错误 找不到Python应用程序 我得到了一些奇怪的错误在我的uwsgi错误文件,你可以在我的文章底部找到。 我会直截了当地说,这是在运行Ubuntu 13.04 64位的新VPS上,这些是我运行的命令。 sudo apt-get更新 sudo apt-get安装构建基本 sudo apt-get安装python-dev sudo

  • 我已经创建了一个blob触发器,它从一个blob接受一个文件,解压缩它,并使用streams将它移动到另一个blob。 我的代码如下所示 实际上,这将在本地运行时使用我的local.settings.json文件中的“azurewebjobstorage”:“UseDevelopmentStorage = true”。 然而,一旦我部署了这个应用程序,并使用Azure Storage Explor