aiohttp 異步http請求-4.文件上傳multipart/form-data


前言

文件上傳接口,post 請求參數類型content-type:multipart/form-data,上傳文件分2種情況

  • 小文件上傳,可以直接用open函數讀取
  • 大文件上傳,aiohttp支持多種類型的文件以流媒體的形式上傳

官方文檔示例

上傳 multipart 類型

url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}

await session.post(url, data=files)

也可以明確設置filenamecontent_type

url = 'http://httpbin.org/post'
data = FormData()
data.add_field('file',
               open('report.xls', 'rb'),
               filename='report.xls',
               content_type='application/vnd.ms-excel')

await session.post(url, data=data)

參考案例

用fiddler抓包,查看抓到的接口,以下這種接口就是multipart/form-data

Content-Type: multipart/form-data
body參數是這種格式:

-----------------------------22165374713946
Content-Disposition: form-data; name="localUrl"

yoyoketang.png
-----------------------------22165374713946
Content-Disposition: form-data; name="imgFile"; filename="yoyoketang.png"
Content-Type: image/png

上面的接口需要傳2個參數

  • title 傳字符串
  • file 傳一個文件

官網文檔寫的是只傳一個file參數,實際驗證也可以傳其它字符串參數,如下示例:

import aiohttp
import asyncio


async def main():
    async with aiohttp.ClientSession('http://127.0.0.1:8000') as session:
        files = {
            'file': open('a.jpg', 'rb'),
            'title': '文件上傳'
            }
        async with session.post('/api/v1/upfile/', data=files) as resp:
            print(resp.url)
            print(await resp.text())


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

運行結果

http://http://127.0.0.1:8000/api/v1/upfile/
{"code":0,"msg":"success!","data":{"file":"/media/up_image/a_TEn5GLR.jpg","title":"文件上傳","timestamp":"2022-04-21 11:15:28"}}

使用 FormData 類

FormData 類自定義文件類型和名稱

import aiohttp
import asyncio
from aiohttp import FormData


async def main():
    async with aiohttp.ClientSession('http://49.235.92.12:7005') as session:
        data = FormData()
        data.add_field('file',
                       open('a.jpg', 'rb'),
                       filename='a.jpg',
                       content_type='image/png')
        data.add_field('title', '文件上傳1')
        async with session.post('/api/v1/upfile/', data=data) as resp:
            print(resp.url)
            print(await resp.text())


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

大文件上傳

小文件上傳可以直接open函數讀取,大文件直接讀取會非常消耗內容。aiohttp支持多種類型的流式上傳,這使您可以發送大文件而無需將它們讀入內存。
作為一個簡單的案例,只需為您的 body 提供一個類似文件的對象:

with open('massive-body', 'rb') as f:
   await session.post('http://httpbin.org/post', data=f)

或者您可以使用異步生成器:

async def file_sender(file_name=None):
    async with aiofiles.open(file_name, 'rb') as f:
        chunk = await f.read(64*1024)
        while chunk:
            yield chunk
            chunk = await f.read(64*1024)

# Then you can use file_sender as a data provider:

async with session.post('http://httpbin.org/post',
                        data=file_sender(file_name='huge_file')) as resp:
    print(await resp.text())

因為該 content 屬性是一個 StreamReader(提供異步迭代器協議),所以您可以將 get 和 post 請求鏈接在一起:

resp = await session.get('http://python.org')
await session.post('http://httpbin.org/post',
                   data=resp.content)

筆記 Python 3.5 沒有對異步生成器的原生支持,使用 async_generator庫作為解決方法。
3.1 版后已棄用:aiohttp仍支持aiohttp.streamer裝飾器,但不推薦使用此方法,而支持異步生成器,如上所示。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM