Python:使用cherrypy通过POST发送和接收大文件

Posted

技术标签:

【中文标题】Python:使用cherrypy通过POST发送和接收大文件【英文标题】:Python: sending and receiving large files over POST using cherrypy 【发布时间】:2012-10-11 17:54:15 【问题描述】:

我有一个cherrypy web 服务器,它需要能够通过http post 接收大文件。我目前有一些工作,但是一旦发送的文件变得太大(大约 200mb),它就会失败。我正在使用 curl 发送测试发布请求,当我尝试发送一个太大的文件时,curl 吐出“与请求一起发送的实体超出了允许的最大字节数。”搜索了一下,这似乎是cherrypy的错误。

所以我猜要发送的文件需要分块发送?我用 mmap 尝试了一些东西,但我无法让它太有效。处理文件上传的方法是否也需要能够接受分块数据?

【问题讨论】:

根据this,您可以尝试将配置值 server.max_request_body_size 设置为更高的值吗? @jobby:您确实应该将其发布为答案,而不是评论。 【参考方案1】:

我以DirectToDiskFileUpload 为起点。它为处理大型上传所做的更改是:

    server.max_request_body_size0(默认 100MB), server.socket_timeout60(默认 10 秒), response.timeout3600(默认 300 秒), 使用tempfile.NamedTemporaryFile 避免重复复制。

还采取了一些无用的操作来避免将上传保存在内存中,这会禁用标准的 CherryPy 主体处理并手动使用 cgi.FieldStorage。没用,因为有cherrypy._cpreqbody.Part.maxrambytes

Part 将存储其数据的字节阈值 在文件而不是字符串中。默认为 1000,就像 cgi 模块 Python 的标准库。

我已尝试使用以下代码(由 Python 2.7.4、CherryPy 3.6 运行)和 1.4GB 文件。内存使用量(在 gnome-system-monitor 中)从未达到 10MiB。根据实际写入磁盘的字节数,cat /proc/PID/iowrite_bytes几乎是文件的大小。使用标准的cherrypy._cpreqbody.Partshutil.copyfileobj 显然翻倍了。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import os
import tempfile

import cherrypy


config = 
  'global' : 
    'server.socket_host' : '127.0.0.1',
    'server.socket_port' : 8080,
    'server.thread_pool' : 8,
    # remove any limit on the request body size; cherrypy's default is 100MB
    'server.max_request_body_size' : 0,
    # increase server socket timeout to 60s; cherrypy's defult is 10s
    'server.socket_timeout' : 60
  



class NamedPart(cherrypy._cpreqbody.Part):

  def make_file(self):
    return tempfile.NamedTemporaryFile()

cherrypy._cpreqbody.Entity.part_class = NamedPart


class App:

  @cherrypy.expose
  def index(self):
    return '''<!DOCTYPE html>
      <html>
      <body>
        <form action='upload' method='post' enctype='multipart/form-data'>
          File: <input type='file' name='videoFile'/> <br/>
          <input type='submit' value='Upload'/>
        </form>
      </body>
      </html>
    '''

  @cherrypy.config(**'response.timeout': 3600) # default is 300s
  @cherrypy.expose()
  def upload(self, videoFile):
    assert isinstance(videoFile, cherrypy._cpreqbody.Part)

    destination = os.path.join('/home/user/', videoFile.filename)

    # Note that original link will be deleted by tempfile.NamedTemporaryFile
    os.link(videoFile.file.name, destination)

    # Double copy with standard ``cherrypy._cpreqbody.Part``
    #import shutil
    #with open(destination, 'wb') as f:
    #  shutil.copyfileobj(videoFile.file, f)

    return 'Okay'


if __name__ == '__main__':
  cherrypy.quickstart(App(), '/', config)

【讨论】:

【参考方案2】:

巨大的文件上传总是有问题的。如果在上传过程中连接关闭,您会怎么做?改用分块文件上传方法。

【讨论】:

以上是关于Python:使用cherrypy通过POST发送和接收大文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CherryPy 的 POST 请求中接收 JSON?

XML 格式的 fileDataBodyPart 未通过 ApacheHttpClient 上传到 CherryPy

在cherrypy中获取原始目标ip

CherryPy:将访问和错误事件记录到 syslog

使用cherrypy(python 2)禁用弱密码

如何使用 CherryPy 配置 IP 地址?