Python: отправка и получение больших файлов через POST с использованием cherrypy

У меня есть веб-сервер cherrypy, который должен иметь возможность получать большие файлы через HTTP-пост. У меня что-то работает в данный момент, но оно перестает работать, когда отправляемые файлы становятся слишком большими (около 200 МБ). Я использую curl для отправки тестовых почтовых запросов, и когда я пытаюсь отправить файл слишком большого размера, curl выдает «Объект, отправленный с запросом, превышает максимально допустимые байты». Поиски вокруг, похоже, ошибка от cherrypy.

Итак, я предполагаю, что отправляемый файл нужно отправлять кусками? Я попробовал кое-что с mmap, но я не мог заставить это работать. Нужно ли методу, который обрабатывает загрузку файла, принимать данные и порциями?

 Mike DeSimone22 окт. 2012 г., 01:30
@jobby: Вы действительно должны опубликовать это как ответ, а не как комментарий.
 jobby22 окт. 2012 г., 00:33
Согласно сэто, вы могли бы попробовать установить значение конфигурации server.max_request_body_size на что-то более высокое?

Ответы на вопрос(2)

DirectToDiskFileUpload в качестве отправной точки. Изменения, которые он делает для обработки больших загрузок:

server.max_request_body_size в0 (по умолчанию 100 МБ),server.socket_timeout в60 (по умолчанию 10 с),response.timeout в3600 (по умолчанию 300 с),Избегайте двойного копирования с помощьюtempfile.NamedTemporaryFile.

Есть также некоторые бесполезные действия, предпринятые, чтобы предположительно избежать задержки загрузки в память, которые отключают стандартную обработку и использование тела CherryPy.cgi.FieldStorage вместо этого вручную. Это бесполезно, потому что естьcherrypy._cpreqbody.Part.maxrambytes.

Порог байтов, после которого указываетсяPart будет хранить свои данные в файле вместо строки. По умолчанию 1000, как иcgi модуль в стандартной библиотеке Python.

Я экспериментировал со следующим кодом (запущенным Python 2.7.4, CherryPy 3.6) и файлом 1.4GB. Использование памяти (вгном-системы мониторинга) никогда не достигал 10MiB. Согласно количеству байтов, фактически записанных на диск,cat /proc/PID/io«swrite_bytes почти размер файла. Со стандартнымcherrypy._cpreqbody.Part а такжеshutil.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)

когда соединение закрывается во время загрузки? Вместо этого используйте метод загрузки фрагментированных файлов.

Ваш ответ на вопрос