aiohttp request.multipart () ничего не получает от загрузки файлов из браузера - PullRequest
0 голосов
/ 25 мая 2018
Браузер

, использующий компонент vue element-ui el-upload для загрузки файла, и aiohttp в качестве бэкэнда получают данные формы, затем сохраняют его. Но aiohttp request.multipart () всегда был пустым, но request.post () будет в порядке.

vue:

   <el-upload class="image-uploader" 
        :data="dataObj" 
         drag 
         name="aaa"
        :multiple="false" 
        :show-file-list="false"
        :action="action"  -> upload url,passed from outer component
        :on-success="handleImageScucess">
      <i class="el-icon-upload"></i>
    </el-upload>

export default {
  name: 'singleImageUpload3',
  props: {
    value: String,
    action: String
  },
  methods: {
   handleImageScucess(file) {
      this.emitInput(file.files.file)
    },

  }

aiohttp: не работает

 async def post_image(self, request):

        reader = await request.multipart()

        image = await reader.next()
        print (image.text())
        filename = image.filename
        print (filename)
        size = 0
        with open(os.path.join('', 'aaa.jpg'), 'wb') as f:
            while True:
                chunk = await image.read_chunk()

                print ("chunk", chunk)
                if not chunk:
                    break
                size += len(chunk)
                f.write(chunk)
        return await self.reply_ok([])

aiohttp: работа

async def post_image(self, request):
        data = await request.post()
        print (data)
        mp3 = data['aaa']

        filename = mp3.filename

        mp3_file = data['aaa'].file

        content = mp3_file.read()
        with open('aaa.jpg', 'wb') as f:
            f.write(content)
        return await self.reply_ok([])

консоль браузера:

enter image description here

ошибка или что-то, что я пропустил?Пожалуйста, помогите мне решить, заранее спасибо.

1 Ответ

0 голосов
/ 30 июля 2019

Я думаю, вы могли бы проверить пример на aiohttp документе о сервере загрузки файлов .Но этот фрагмент неоднозначен, и документ не очень хорошо объясняет себя.

Поработав некоторое время над его исходным кодом, я обнаружил, что request.multipart() на самом деле дает экземпляр MultipartReader, который обрабатывает multipart/form-data запросов по одному полю каждый раз при вызове .next(), давая другое BodyPartReader instance.

В вашем неработающем коде image = await reader.next() эта строка фактически считывает одно целое поле из данных формы, и вы не можете быть уверены, какое это поле на самом деле.Это может быть поле token, поле key, поле filename, поле aaa ... или любое из них.Таким образом, в вашем неработающем примере эта функция сопрограммы post_image будет обрабатывать только одно поле из запрашиваемых вами данных, и вы не можете быть уверены, что это поле aaa file.

Вот мой фрагмент кода,

async def post_image(self, request):
    # Iterate through each field of MultipartReader
    async for field in (await request.multipart()):
        if field.name == 'token':
            # Do something about token
            token = (await field.read()).decode()
            pass

        if field.name == 'key':
            # Do something about key
            pass

        if field.name == 'filename':
            # Do something about filename
            pass

        if field.name == 'aaa':
            # Process any files you uploaded
            filename = field.filename
            # In your example, filename should be "2C80...jpg"

            # Deal with actual file data
            size = 0
            with open(os.path.join('', filename), 'wb') as fd:
                while True:
                    chunk = await field.read_chunk()
                    if not chunk:
                        break
                    size += len(chunk)
                    fd.write(chunk)

    # Reply ok, all fields processed successfully
    return await self.reply_ok([])

И приведенный выше фрагмент также может работать с несколькими файлами в одном запросе с повторяющимся именем поля, или 'aaa' в вашем примере.Заголовок filename in Content-Disposition должен автоматически заполняться самим браузером, поэтому не нужно беспокоиться о filename.

Кстати, при работе с загрузками файлов в запросах data = await request.post() будет съедатьзначительное количество памяти для загрузки файловых данных.Поэтому при загрузке файлов следует избегать request.post(), вместо этого используйте request.multipart().

...