Search code examples
pythonmultipartform-dataaiohttp

aiohttp.ClientSession multipart/form-data


I have a curl request:

# form data: id = 247, name = Test
curl '{HOST}' \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundarywiBIWjWR7osAkgFI' \
  --data-raw $'------WebKitFormBoundarywiBIWjWR7osAkgFI\r\nContent-Disposition: form-data; name="id"\r\n\r\n247\r\n' \
              '------WebKitFormBoundarywiBIWjWR7osAkgFI\r\nContent-Disposition: form-data; name="name"\r\n\r\nTest\r\n' \
              '------WebKitFormBoundarywiBIWjWR7osAkgFI--\r\n'

To send the same request using requests + requests_toolbelt:

mp = MultipartEncoder(
   fields={'id': '247', 'name': 'Test'},
   boundary='----WebKitFormBoundarywiBIWjWR7osAkgFI'
)

answer = requests.post(
    '{HOST}',
    data=mp,
    headers={'Content-Type': mp.content_type })

But how can I send the same request using aiohttp.ClientSession? I have tried to use MultipartWriter + set_content_disposition() or FormData + add_field() but apparently I'm doing something wrong


Solution

  • In my case works fine:

    boundary = '----WebKitFormBoundarywiBIWjWR7osAkgFI'
    with aiohttp.MultipartWriter('form-data', boundary) as writer:
        # custom headers...
        # writer.headers['User-Agent'] = '...'
    
        data = {'id': '247', 'name': 'Test'}
        for key, value in data.items():
            part = writer.append(value, {'content-type': 'form-data'})
            part.set_content_disposition('form-data', name=key)
    
        async with session.post('{HOST}', data=writer) as resp:
            data = await resp.json()
    

    JFYI: you can use quote_fields=False if you need to send form fields:

    part = writer.append('VALUE', {'content-type': 'form-data'})
    part.set_content_disposition('form-data', False, name='form_fields[field_0]')
    

    Result:

    ------WebKitFormBoundaryGWdKpzFAElN34726\r\nContent-Disposition: form-data; name="form_fields[field_0]"\r\n\r\nVALUE\r\n