Handling Multipart Responses with AIOHTTP in Python
Multipart responses enable you to send multiple data types in a single HTTP response.
They allow you to combine text, JSON, binary files, and even HTML content in one package.
In this tutorial, you’ll learn how to create, handle, and parse multipart responses using AIOHTTP.
Create Multipart Responses
To create a multipart response, you can use the aiohttp.MultipartWriter
class.
This allows you to construct responses with multiple parts, each having its own headers and content.
from aiohttp import web from aiohttp.multipart import MultipartWriter async def handle_multipart(request): writer = MultipartWriter('mixed') response = web.StreamResponse() response.content_type = 'multipart/mixed' await response.prepare(request) # Add parts to the writer await writer.write(response) return response app = web.Application() app.router.add_get('/multipart', handle_multipart)
The MultipartWriter
is initialized with the ‘mixed’ subtype.
Handle Different Content Types
Text Content
Add plain text content to your multipart response easily.
text_content = "Hello, this is a sample text content." text_part = writer.append(text_content) text_part.headers['Content-Type'] = 'text/plain'
Plain text is added as a separate part in the multipart response so the clients can extract and display text easily.
JSON Data
Include structured data in your response using JSON.
json_data = { "user": { "name": "Alice Smith", "email": "alice@example.com", "age": 28 }, "preferences": ["python", "asyncio", "web development"] } json_part = writer.append_json(json_data)
JSON data is serialized and added as a separate part, allowing for easy parsing and use by the client.
Binary Data (Files, Images)
You can include binary data such as images in your multipart response.
with open('logo.png', 'rb') as f: image_data = f.read() img_part = writer.append(image_data, {'Content-Type': 'image/png'}) img_part.set_content_disposition('attachment', filename='company_logo.png')
Binary data is read from a file and added as a part of the multipart response.
HTML Content
You can include formatted HTML content in your multipart response.
html_content = """ <html> <body> <h1>Welcome to AIOHTTP Multipart Tutorial</h1> <p>This is a sample HTML content in a multipart response.</p> </body> </html> """ html_part = writer.append(html_content) html_part.headers['Content-Type'] = 'text/html'
This allows clients to render it as a formatted web page if needed.
Read Multipart Responses
You can use aiohttp.MultipartReader
to parse multipart responses on the client side.
import aiohttp async def fetch_multipart(): async with aiohttp.ClientSession() as session: async with session.get('http://example.com/multipart') as resp: reader = aiohttp.MultipartReader.from_response(resp) # Process parts here
This code prepares a client to receive and parse a multipart response using MultipartReader
to handle the incoming data.
Extract Different Parts from the Response
You can process each part of the multipart response based on its content type.
async def process_parts(reader): async for part in reader: if part.headers['Content-Type'] == 'text/plain': text = await part.text() print(f"Text content: {text}") elif part.headers['Content-Type'] == 'application/json': json_data = await part.json() print(f"JSON data: {json_data}") elif part.headers['Content-Type'] == 'image/png': filename = part.filename or 'image.png' with open(filename, 'wb') as f: f.write(await part.read()) print(f"Saved image: {filename}") elif part.headers['Content-Type'] == 'text/html': html = await part.text() print(f"HTML content: {html[:100]}...") # Print first 100 chars
Output:
Text content: Hello, this is a sample text content. JSON data: {'user': {'name': 'Alice Smith', 'email': 'alice@example.com', 'age': 28}, 'preferences': ['python', 'asyncio', 'web development']} Saved image: company_logo.png HTML content: <html><body><h1>Welcome to AIOHTTP Multipart Tutorial</h1><p>This is a sample HTML content in a...
This code processes each part of the multipart response according to its content type.
Nested Multipart Responses
You can handle nested multipart responses by recursively processing parts.
async def process_nested_multipart(part): if part.headers['Content-Type'].startswith('multipart/'): nested_reader = await part.multipart() async for nested_part in nested_reader: await process_nested_multipart(nested_part) else: # Process the part as before pass async def handle_response(resp): reader = aiohttp.MultipartReader.from_response(resp) async for part in reader: await process_nested_multipart(part)
This recursive method allows you to handle multipart responses of any depth.
Compress Individual Parts
You can compress large parts to reduce response size by comprising the data and setting the suitable encoding:
import zlib def compress_data(data): return zlib.compress(data.encode() if isinstance(data, str) else data) async def compressed_multipart(request): writer = MultipartWriter() large_text = "A" * 10000 # 10KB of data compressed = compress_data(large_text) part = writer.append(compressed) part.headers['Content-Type'] = 'text/plain' part.headers['Content-Encoding'] = 'deflate' response = web.StreamResponse() response.content_type = 'multipart/mixed' await response.prepare(request) await writer.write(response) return response
Compressing large parts of a multipart response can significantly reduce the amount of data transferred.
Mokhtar is the founder of LikeGeeks.com. He is a seasoned technologist and accomplished author, with expertise in Linux system administration and Python development. Since 2010, Mokhtar has built an impressive career, transitioning from system administration to Python development in 2015. His work spans large corporations to freelance clients around the globe. Alongside his technical work, Mokhtar has authored some insightful books in his field. Known for his innovative solutions, meticulous attention to detail, and high-quality work, Mokhtar continually seeks new challenges within the dynamic field of technology.