0
# Utilities
1
2
Supporting utilities and extensions including request tracing, DNS resolution, authentication helpers, compression configuration, and Gunicorn worker integration. These utilities provide integration points, performance optimization, and extensibility features for aiohttp applications.
3
4
## Capabilities
5
6
### Request Tracing
7
8
Comprehensive request tracing system for monitoring and debugging HTTP client operations with detailed event tracking.
9
10
```python { .api }
11
class TraceConfig:
12
def __init__(self):
13
"""Create trace configuration."""
14
15
def on_request_start(self, callback):
16
"""
17
Register request start callback.
18
19
Parameters:
20
- callback: Async function receiving TraceRequestStartParams
21
"""
22
23
def on_request_end(self, callback):
24
"""
25
Register request end callback.
26
27
Parameters:
28
- callback: Async function receiving TraceRequestEndParams
29
"""
30
31
def on_request_exception(self, callback):
32
"""
33
Register request exception callback.
34
35
Parameters:
36
- callback: Async function receiving TraceRequestExceptionParams
37
"""
38
39
def on_request_redirect(self, callback):
40
"""
41
Register request redirect callback.
42
43
Parameters:
44
- callback: Async function receiving TraceRequestRedirectParams
45
"""
46
47
def on_request_headers_sent(self, callback):
48
"""
49
Register request headers sent callback.
50
51
Parameters:
52
- callback: Async function receiving TraceRequestHeadersSentParams
53
"""
54
55
def on_request_chunk_sent(self, callback):
56
"""
57
Register request chunk sent callback.
58
59
Parameters:
60
- callback: Async function receiving TraceRequestChunkSentParams
61
"""
62
63
def on_response_chunk_received(self, callback):
64
"""
65
Register response chunk received callback.
66
67
Parameters:
68
- callback: Async function receiving TraceResponseChunkReceivedParams
69
"""
70
71
def on_connection_create_start(self, callback):
72
"""
73
Register connection creation start callback.
74
75
Parameters:
76
- callback: Async function receiving TraceConnectionCreateStartParams
77
"""
78
79
def on_connection_create_end(self, callback):
80
"""
81
Register connection creation end callback.
82
83
Parameters:
84
- callback: Async function receiving TraceConnectionCreateEndParams
85
"""
86
87
def on_connection_queued_start(self, callback):
88
"""
89
Register connection queued start callback.
90
91
Parameters:
92
- callback: Async function receiving TraceConnectionQueuedStartParams
93
"""
94
95
def on_connection_queued_end(self, callback):
96
"""
97
Register connection queued end callback.
98
99
Parameters:
100
- callback: Async function receiving TraceConnectionQueuedEndParams
101
"""
102
103
def on_connection_reuseconn(self, callback):
104
"""
105
Register connection reuse callback.
106
107
Parameters:
108
- callback: Async function receiving TraceConnectionReuseconnParams
109
"""
110
111
def on_dns_resolvehost_start(self, callback):
112
"""
113
Register DNS resolve start callback.
114
115
Parameters:
116
- callback: Async function receiving TraceDnsResolveHostStartParams
117
"""
118
119
def on_dns_resolvehost_end(self, callback):
120
"""
121
Register DNS resolve end callback.
122
123
Parameters:
124
- callback: Async function receiving TraceDnsResolveHostEndParams
125
"""
126
127
def on_dns_cache_hit(self, callback):
128
"""
129
Register DNS cache hit callback.
130
131
Parameters:
132
- callback: Async function receiving TraceDnsCacheHitParams
133
"""
134
135
def on_dns_cache_miss(self, callback):
136
"""
137
Register DNS cache miss callback.
138
139
Parameters:
140
- callback: Async function receiving TraceDnsCacheMissParams
141
"""
142
143
# Trace event parameter classes
144
class TraceRequestStartParams:
145
"""Request start trace parameters."""
146
@property
147
def method(self): ...
148
@property
149
def url(self): ...
150
@property
151
def headers(self): ...
152
153
class TraceRequestEndParams:
154
"""Request end trace parameters."""
155
@property
156
def method(self): ...
157
@property
158
def url(self): ...
159
@property
160
def headers(self): ...
161
@property
162
def response(self): ...
163
164
class TraceRequestExceptionParams:
165
"""Request exception trace parameters."""
166
@property
167
def method(self): ...
168
@property
169
def url(self): ...
170
@property
171
def headers(self): ...
172
@property
173
def exception(self): ...
174
175
class TraceRequestRedirectParams:
176
"""Request redirect trace parameters."""
177
@property
178
def method(self): ...
179
@property
180
def url(self): ...
181
@property
182
def headers(self): ...
183
@property
184
def response(self): ...
185
186
class TraceRequestHeadersSentParams:
187
"""Request headers sent trace parameters."""
188
@property
189
def method(self): ...
190
@property
191
def url(self): ...
192
@property
193
def headers(self): ...
194
195
class TraceRequestChunkSentParams:
196
"""Request chunk sent trace parameters."""
197
@property
198
def method(self): ...
199
@property
200
def url(self): ...
201
@property
202
def chunk(self): ...
203
204
class TraceResponseChunkReceivedParams:
205
"""Response chunk received trace parameters."""
206
@property
207
def method(self): ...
208
@property
209
def url(self): ...
210
@property
211
def chunk(self): ...
212
213
class TraceConnectionCreateStartParams:
214
"""Connection creation start trace parameters."""
215
pass
216
217
class TraceConnectionCreateEndParams:
218
"""Connection creation end trace parameters."""
219
pass
220
221
class TraceConnectionQueuedStartParams:
222
"""Connection queued start trace parameters."""
223
pass
224
225
class TraceConnectionQueuedEndParams:
226
"""Connection queued end trace parameters."""
227
pass
228
229
class TraceConnectionReuseconnParams:
230
"""Connection reuse trace parameters."""
231
pass
232
233
class TraceDnsResolveHostStartParams:
234
"""DNS resolve start trace parameters."""
235
@property
236
def host(self): ...
237
238
class TraceDnsResolveHostEndParams:
239
"""DNS resolve end trace parameters."""
240
@property
241
def host(self): ...
242
243
class TraceDnsCacheHitParams:
244
"""DNS cache hit trace parameters."""
245
@property
246
def host(self): ...
247
248
class TraceDnsCacheMissParams:
249
"""DNS cache miss trace parameters."""
250
@property
251
def host(self): ...
252
```
253
254
### DNS Resolution
255
256
Configurable DNS resolution with support for different resolver implementations and caching strategies.
257
258
```python { .api }
259
class AsyncResolver:
260
def __init__(self, loop=None):
261
"""
262
Asynchronous DNS resolver.
263
264
Parameters:
265
- loop: Event loop
266
"""
267
268
async def resolve(self, hostname, port=0, family=0):
269
"""
270
Resolve hostname to addresses.
271
272
Parameters:
273
- hostname (str): Hostname to resolve
274
- port (int): Port number
275
- family (int): Address family
276
277
Returns:
278
List of resolved addresses
279
"""
280
281
async def close(self):
282
"""Close resolver resources."""
283
284
class DefaultResolver:
285
def __init__(self, loop=None):
286
"""
287
Default system DNS resolver.
288
289
Parameters:
290
- loop: Event loop
291
"""
292
293
async def resolve(self, hostname, port=0, family=0):
294
"""Resolve hostname using system resolver."""
295
296
async def close(self):
297
"""Close resolver resources."""
298
299
class ThreadedResolver:
300
def __init__(self, loop=None):
301
"""
302
Thread-based DNS resolver.
303
304
Parameters:
305
- loop: Event loop
306
"""
307
308
async def resolve(self, hostname, port=0, family=0):
309
"""Resolve hostname in thread pool."""
310
311
async def close(self):
312
"""Close resolver resources."""
313
```
314
315
### Helper Classes and Functions
316
317
Utility classes and functions for common operations and data structures.
318
319
```python { .api }
320
class ChainMapProxy:
321
def __init__(self, maps):
322
"""
323
Chain map proxy for nested dictionaries.
324
325
Parameters:
326
- maps: Sequence of dictionaries to chain
327
"""
328
329
def __getitem__(self, key):
330
"""Get item from chained maps."""
331
332
def __contains__(self, key):
333
"""Check if key exists in any map."""
334
335
def get(self, key, default=None):
336
"""Get item with default value."""
337
338
def keys(self):
339
"""Get all keys from chained maps."""
340
341
def values(self):
342
"""Get all values from chained maps."""
343
344
def items(self):
345
"""Get all items from chained maps."""
346
347
class ETag:
348
def __init__(self, value, is_weak=False):
349
"""
350
ETag header handling.
351
352
Parameters:
353
- value (str): ETag value
354
- is_weak (bool): Whether ETag is weak
355
"""
356
357
@property
358
def value(self):
359
"""ETag value."""
360
361
@property
362
def is_weak(self):
363
"""Whether ETag is weak."""
364
365
def __str__(self):
366
"""String representation of ETag."""
367
368
class Fingerprint:
369
def __init__(self, fingerprint):
370
"""
371
SSL certificate fingerprint handling.
372
373
Parameters:
374
- fingerprint (bytes): Certificate fingerprint
375
"""
376
377
def check(self, transport):
378
"""
379
Verify certificate fingerprint.
380
381
Parameters:
382
- transport: SSL transport
383
384
Raises:
385
ServerFingerprintMismatch: If fingerprint doesn't match
386
"""
387
388
class RequestInfo:
389
def __init__(self, url, method, headers, real_url=None):
390
"""
391
Request information container.
392
393
Parameters:
394
- url: Request URL
395
- method (str): HTTP method
396
- headers: Request headers
397
- real_url: Real URL after redirects
398
"""
399
400
@property
401
def url(self):
402
"""Request URL."""
403
404
@property
405
def method(self):
406
"""HTTP method."""
407
408
@property
409
def headers(self):
410
"""Request headers."""
411
412
@property
413
def real_url(self):
414
"""Real URL after redirects."""
415
```
416
417
### Compression Configuration
418
419
Compression backend configuration for optimized data processing.
420
421
```python { .api }
422
def set_zlib_backend(backend):
423
"""
424
Configure zlib backend for compression.
425
426
Parameters:
427
- backend (str): Backend name ('zlib' or 'brotli')
428
"""
429
```
430
431
### Gunicorn Worker Integration
432
433
Gunicorn worker classes for deploying aiohttp applications in production environments.
434
435
```python { .api }
436
class GunicornWebWorker:
437
"""Gunicorn worker for aiohttp applications."""
438
439
def __init__(self, age, ppid, sockets, app, log, cfg):
440
"""
441
Initialize Gunicorn worker.
442
443
Parameters:
444
- age: Worker age
445
- ppid: Parent process ID
446
- sockets: Server sockets
447
- app: WSGI application
448
- log: Logger instance
449
- cfg: Gunicorn configuration
450
"""
451
452
def init_process(self):
453
"""Initialize worker process."""
454
455
def run(self):
456
"""Run worker main loop."""
457
458
class GunicornUVLoopWebWorker(GunicornWebWorker):
459
"""Gunicorn worker with uvloop for enhanced performance."""
460
461
def init_process(self):
462
"""Initialize worker with uvloop."""
463
```
464
465
### HTTP Headers Module
466
467
Complete set of HTTP header constants and utilities.
468
469
```python { .api }
470
# HTTP method constants
471
METH_ANY = '*'
472
METH_CONNECT = 'CONNECT'
473
METH_HEAD = 'HEAD'
474
METH_GET = 'GET'
475
METH_DELETE = 'DELETE'
476
METH_OPTIONS = 'OPTIONS'
477
METH_PATCH = 'PATCH'
478
METH_POST = 'POST'
479
METH_PUT = 'PUT'
480
METH_TRACE = 'TRACE'
481
482
# Set of all HTTP methods
483
METH_ALL = frozenset([
484
METH_CONNECT, METH_HEAD, METH_GET, METH_DELETE,
485
METH_OPTIONS, METH_PATCH, METH_POST, METH_PUT, METH_TRACE
486
])
487
488
# HTTP header constants (istr objects for case-insensitive comparison)
489
ACCEPT = 'Accept'
490
ACCEPT_CHARSET = 'Accept-Charset'
491
ACCEPT_ENCODING = 'Accept-Encoding'
492
ACCEPT_LANGUAGE = 'Accept-Language'
493
ACCEPT_RANGES = 'Accept-Ranges'
494
ACCESS_CONTROL_ALLOW_CREDENTIALS = 'Access-Control-Allow-Credentials'
495
ACCESS_CONTROL_ALLOW_HEADERS = 'Access-Control-Allow-Headers'
496
ACCESS_CONTROL_ALLOW_METHODS = 'Access-Control-Allow-Methods'
497
ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'
498
ACCESS_CONTROL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers'
499
ACCESS_CONTROL_MAX_AGE = 'Access-Control-Max-Age'
500
ACCESS_CONTROL_REQUEST_HEADERS = 'Access-Control-Request-Headers'
501
ACCESS_CONTROL_REQUEST_METHOD = 'Access-Control-Request-Method'
502
AGE = 'Age'
503
ALLOW = 'Allow'
504
AUTHORIZATION = 'Authorization'
505
CACHE_CONTROL = 'Cache-Control'
506
CONNECTION = 'Connection'
507
CONTENT_DISPOSITION = 'Content-Disposition'
508
CONTENT_ENCODING = 'Content-Encoding'
509
CONTENT_LANGUAGE = 'Content-Language'
510
CONTENT_LENGTH = 'Content-Length'
511
CONTENT_LOCATION = 'Content-Location'
512
CONTENT_MD5 = 'Content-MD5'
513
CONTENT_RANGE = 'Content-Range'
514
CONTENT_TRANSFER_ENCODING = 'Content-Transfer-Encoding'
515
CONTENT_TYPE = 'Content-Type'
516
COOKIE = 'Cookie'
517
DATE = 'Date'
518
DESTINATION = 'Destination'
519
DIGEST = 'Digest'
520
ETAG = 'ETag'
521
EXPECT = 'Expect'
522
EXPIRES = 'Expires'
523
FORWARDED = 'Forwarded'
524
FROM = 'From'
525
HOST = 'Host'
526
IF_MATCH = 'If-Match'
527
IF_MODIFIED_SINCE = 'If-Modified-Since'
528
IF_NONE_MATCH = 'If-None-Match'
529
IF_RANGE = 'If-Range'
530
IF_UNMODIFIED_SINCE = 'If-Unmodified-Since'
531
LAST_MODIFIED = 'Last-Modified'
532
LINK = 'Link'
533
LOCATION = 'Location'
534
MAX_FORWARDS = 'Max-Forwards'
535
ORIGIN = 'Origin'
536
PRAGMA = 'Pragma'
537
PROXY_AUTHENTICATE = 'Proxy-Authenticate'
538
PROXY_AUTHORIZATION = 'Proxy-Authorization'
539
RANGE = 'Range'
540
REFERER = 'Referer'
541
RETRY_AFTER = 'Retry-After'
542
SEC_WEBSOCKET_ACCEPT = 'Sec-WebSocket-Accept'
543
SEC_WEBSOCKET_KEY = 'Sec-WebSocket-Key'
544
SEC_WEBSOCKET_KEY1 = 'Sec-WebSocket-Key1'
545
SEC_WEBSOCKET_KEY2 = 'Sec-WebSocket-Key2'
546
SEC_WEBSOCKET_ORIGIN = 'Sec-WebSocket-Origin'
547
SEC_WEBSOCKET_PROTOCOL = 'Sec-WebSocket-Protocol'
548
SEC_WEBSOCKET_VERSION = 'Sec-WebSocket-Version'
549
SERVER = 'Server'
550
SET_COOKIE = 'Set-Cookie'
551
TE = 'TE'
552
TRAILER = 'Trailer'
553
TRANSFER_ENCODING = 'Transfer-Encoding'
554
UPGRADE = 'Upgrade'
555
URI = 'URI'
556
USER_AGENT = 'User-Agent'
557
VARY = 'Vary'
558
VIA = 'Via'
559
WARNING = 'Warning'
560
WWW_AUTHENTICATE = 'WWW-Authenticate'
561
X_FORWARDED_FOR = 'X-Forwarded-For'
562
X_FORWARDED_HOST = 'X-Forwarded-Host'
563
X_FORWARDED_PROTO = 'X-Forwarded-Proto'
564
```
565
566
## Usage Examples
567
568
### Request Tracing for Performance Monitoring
569
570
```python
571
import aiohttp
572
import asyncio
573
import time
574
575
async def setup_tracing():
576
"""Setup comprehensive request tracing."""
577
trace_config = aiohttp.TraceConfig()
578
579
# Request lifecycle tracking
580
async def on_request_start(session, context, params):
581
context.start_time = time.time()
582
print(f"Starting request: {params.method} {params.url}")
583
584
async def on_request_end(session, context, params):
585
duration = time.time() - context.start_time
586
print(f"Request completed: {params.method} {params.url} "
587
f"({params.response.status}) in {duration:.3f}s")
588
589
async def on_request_exception(session, context, params):
590
duration = time.time() - context.start_time
591
print(f"Request failed: {params.method} {params.url} "
592
f"after {duration:.3f}s - {params.exception}")
593
594
# Connection tracking
595
async def on_connection_create_start(session, context, params):
596
print("Creating new connection...")
597
598
async def on_connection_create_end(session, context, params):
599
print("Connection created successfully")
600
601
async def on_connection_reuseconn(session, context, params):
602
print("Reusing existing connection")
603
604
# DNS tracking
605
async def on_dns_resolvehost_start(session, context, params):
606
print(f"Resolving DNS for {params.host}")
607
608
async def on_dns_resolvehost_end(session, context, params):
609
print(f"DNS resolved for {params.host}")
610
611
async def on_dns_cache_hit(session, context, params):
612
print(f"DNS cache hit for {params.host}")
613
614
# Register callbacks
615
trace_config.on_request_start(on_request_start)
616
trace_config.on_request_end(on_request_end)
617
trace_config.on_request_exception(on_request_exception)
618
trace_config.on_connection_create_start(on_connection_create_start)
619
trace_config.on_connection_create_end(on_connection_create_end)
620
trace_config.on_connection_reuseconn(on_connection_reuseconn)
621
trace_config.on_dns_resolvehost_start(on_dns_resolvehost_start)
622
trace_config.on_dns_resolvehost_end(on_dns_resolvehost_end)
623
trace_config.on_dns_cache_hit(on_dns_cache_hit)
624
625
return trace_config
626
627
async def traced_requests():
628
"""Make requests with tracing enabled."""
629
trace_config = await setup_tracing()
630
631
async with aiohttp.ClientSession(trace_configs=[trace_config]) as session:
632
# Make multiple requests to see tracing in action
633
urls = [
634
'https://httpbin.org/delay/1',
635
'https://httpbin.org/json',
636
'https://httpbin.org/status/200',
637
'https://httpbin.org/delay/1' # This should reuse connection
638
]
639
640
for url in urls:
641
try:
642
async with session.get(url) as response:
643
await response.read()
644
except Exception as e:
645
print(f"Request error: {e}")
646
647
# Run traced requests
648
asyncio.run(traced_requests())
649
```
650
651
### Custom DNS Resolver
652
653
```python
654
import aiohttp
655
import asyncio
656
import socket
657
658
class CustomResolver(aiohttp.AsyncResolver):
659
"""Custom DNS resolver with local overrides."""
660
661
def __init__(self, overrides=None, loop=None):
662
super().__init__(loop=loop)
663
self.overrides = overrides or {}
664
665
async def resolve(self, hostname, port=0, family=socket.AF_UNSPEC):
666
"""Resolve with local overrides."""
667
if hostname in self.overrides:
668
# Use override address
669
override_addr = self.overrides[hostname]
670
return [{
671
'hostname': hostname,
672
'host': override_addr,
673
'port': port,
674
'family': socket.AF_INET,
675
'proto': 0,
676
'flags': 0
677
}]
678
679
# Use default resolution
680
return await super().resolve(hostname, port, family)
681
682
async def use_custom_resolver():
683
"""Use custom DNS resolver."""
684
# Map hostnames to custom addresses
685
resolver = CustomResolver(overrides={
686
'api.local': '127.0.0.1',
687
'dev.example.com': '192.168.1.100'
688
})
689
690
connector = aiohttp.TCPConnector(resolver=resolver)
691
692
async with aiohttp.ClientSession(connector=connector) as session:
693
# This will resolve api.local to 127.0.0.1
694
try:
695
async with session.get('http://api.local:8080/test') as response:
696
return await response.text()
697
except aiohttp.ClientError as e:
698
print(f"Request failed: {e}")
699
700
asyncio.run(use_custom_resolver())
701
```
702
703
### Helper Utilities Usage
704
705
```python
706
from aiohttp.helpers import ChainMapProxy, ETag, BasicAuth
707
import aiohttp
708
709
def demonstrate_helpers():
710
"""Demonstrate utility helper classes."""
711
712
# ChainMapProxy for nested configuration
713
default_config = {'timeout': 30, 'retries': 3}
714
user_config = {'timeout': 60}
715
runtime_config = {'debug': True}
716
717
config = ChainMapProxy([runtime_config, user_config, default_config])
718
719
print(f"Timeout: {config['timeout']}") # 60 (from user_config)
720
print(f"Retries: {config['retries']}") # 3 (from default_config)
721
print(f"Debug: {config['debug']}") # True (from runtime_config)
722
723
# ETag handling
724
etag = ETag('abc123', is_weak=False)
725
print(f"ETag: {etag}") # "abc123"
726
727
weak_etag = ETag('def456', is_weak=True)
728
print(f"Weak ETag: {weak_etag}") # W/"def456"
729
730
# Basic authentication
731
auth = BasicAuth('username', 'password')
732
print(f"Auth login: {auth.login}")
733
print(f"Auth password: {auth.password}")
734
735
demonstrate_helpers()
736
```
737
738
### Production Deployment with Gunicorn
739
740
```python
741
# gunicorn_config.py - Gunicorn configuration file
742
import multiprocessing
743
744
# Server socket
745
bind = "0.0.0.0:8000"
746
backlog = 2048
747
748
# Worker processes
749
workers = multiprocessing.cpu_count() * 2 + 1
750
worker_class = "aiohttp.GunicornWebWorker"
751
worker_connections = 1000
752
max_requests = 1000
753
max_requests_jitter = 50
754
timeout = 30
755
keepalive = 2
756
757
# Logging
758
accesslog = "-"
759
errorlog = "-"
760
loglevel = "info"
761
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
762
763
# Process naming
764
proc_name = 'aiohttp_app'
765
766
# Server mechanics
767
daemon = False
768
pidfile = '/tmp/aiohttp_app.pid'
769
user = None
770
group = None
771
tmp_upload_dir = None
772
773
# SSL (if needed)
774
# keyfile = '/path/to/keyfile'
775
# certfile = '/path/to/certfile'
776
```
777
778
```python
779
# app.py - Application setup for Gunicorn
780
from aiohttp import web
781
import os
782
import logging
783
784
logging.basicConfig(level=logging.INFO)
785
logger = logging.getLogger(__name__)
786
787
async def health_check(request):
788
"""Health check endpoint."""
789
return web.json_response({'status': 'healthy'})
790
791
async def api_endpoint(request):
792
"""Sample API endpoint."""
793
return web.json_response({
794
'message': 'Hello from aiohttp!',
795
'worker_pid': os.getpid()
796
})
797
798
def create_app():
799
"""Create and configure the application."""
800
app = web.Application()
801
802
# Add routes
803
app.router.add_get('/health', health_check)
804
app.router.add_get('/api/hello', api_endpoint)
805
806
# Add middleware for logging
807
@web.middleware
808
async def logging_middleware(request, handler):
809
start_time = time.time()
810
response = await handler(request)
811
process_time = time.time() - start_time
812
logger.info(f"{request.method} {request.path} - {response.status} - {process_time:.3f}s")
813
return response
814
815
app.middlewares.append(logging_middleware)
816
817
# Startup/shutdown hooks
818
async def init_app(app):
819
logger.info("Application starting up...")
820
821
async def cleanup_app(app):
822
logger.info("Application shutting down...")
823
824
app.on_startup.append(init_app)
825
app.on_cleanup.append(cleanup_app)
826
827
return app
828
829
# For Gunicorn
830
app = create_app()
831
832
# For development
833
if __name__ == '__main__':
834
web.run_app(app, host='localhost', port=8000)
835
```
836
837
```bash
838
# Deploy with Gunicorn
839
gunicorn app:app -c gunicorn_config.py
840
841
# Or with uvloop for better performance
842
pip install uvloop
843
gunicorn app:app -c gunicorn_config.py --worker-class aiohttp.GunicornUVLoopWebWorker
844
```
845
846
### Compression Configuration
847
848
```python
849
import aiohttp
850
851
# Configure compression backend
852
aiohttp.set_zlib_backend('zlib') # Use standard zlib
853
# aiohttp.set_zlib_backend('brotli') # Use Brotli compression
854
855
async def compressed_request():
856
"""Make request with compression support."""
857
headers = {
858
'Accept-Encoding': 'gzip, deflate, br' # Support multiple encodings
859
}
860
861
async with aiohttp.ClientSession() as session:
862
async with session.get('https://httpbin.org/gzip',
863
headers=headers) as response:
864
# Response is automatically decompressed
865
data = await response.json()
866
return data
867
```