• aiohttp 异步http请求4.文件上传multipart/formdata 上海


    前言

    文件上传接口,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装饰器,但不推荐使用此方法,而支持异步生成器,如上所示。

  • 相关阅读:
    spring中@Lookup的作用
    spring中的观察者模式
    spring事务源码解析
    spring中@Configuration注解的作用
    HTML5和CSS3
    TCP/IP协议
    Android项目的settings.gradle和build.gradle
    AndroidManifest.xml 最全详解
    Android实现网络监听
    Android数据存取
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/16173424.html
Copyright © 2020-2023  润新知