@@ -2,7 +2,7 @@ HTTPX's `Client` also accepts a `transport` argument. This argument allows you
2
2
to provide a custom Transport object that will be used to perform the actual
3
3
sending of the requests.
4
4
5
- ## HTTPTransport
5
+ ## HTTP Transport
6
6
7
7
For some advanced configuration you might need to instantiate a transport
8
8
class directly, and pass it to the client instance. One example is the
@@ -83,7 +83,7 @@ with httpx.Client(transport=transport, base_url="http://testserver") as client:
83
83
...
84
84
```
85
85
86
- ## ASGITransport
86
+ ## ASGI Transport
87
87
88
88
You can configure an ` httpx ` client to call directly into an async Python web application using the ASGI protocol.
89
89
@@ -148,7 +148,7 @@ However it is suggested to use `LifespanManager` from [asgi-lifespan](https://gi
148
148
149
149
## Custom transports
150
150
151
- A transport instance must implement the low-level Transport API, which deals
151
+ A transport instance must implement the low-level Transport API which deals
152
152
with sending a single request, and returning a response. You should either
153
153
subclass ` httpx.BaseTransport ` to implement a transport to use with ` Client ` ,
154
154
or subclass ` httpx.AsyncBaseTransport ` to implement a transport to
@@ -166,28 +166,81 @@ A complete example of a custom transport implementation would be:
166
166
import json
167
167
import httpx
168
168
169
-
170
169
class HelloWorldTransport (httpx .BaseTransport ):
171
170
"""
172
171
A mock transport that always returns a JSON "Hello, world!" response.
173
172
"""
174
173
175
174
def handle_request (self , request ):
176
- message = {" text" : " Hello, world!" }
177
- content = json.dumps(message).encode(" utf-8" )
178
- stream = httpx.ByteStream(content)
179
- headers = [(b " content-type" , b " application/json" )]
180
- return httpx.Response(200 , headers = headers, stream = stream)
175
+ return httpx.Response(200 , json = {" text" : " Hello, world!" })
181
176
```
182
177
183
- Which we can use in the same way:
178
+ Or this example, which uses a custom transport and ` httpx.Mounts ` to always redirect ` http:// ` requests.
184
179
185
- ``` pycon
186
- >>> import httpx
187
- >>> client = httpx.Client(transport = HelloWorldTransport())
188
- >>> response = client.get(" https://example.org/" )
189
- >>> response.json()
190
- {"text": "Hello, world!"}
180
+ ``` python
181
+ class HTTPSRedirect (httpx .BaseTransport ):
182
+ """
183
+ A transport that always redirects to HTTPS.
184
+ """
185
+ def handle_request (self , request ):
186
+ url = request.url.copy_with(scheme = " https" )
187
+ return httpx.Response(303 , headers = {" Location" : str (url)})
188
+
189
+ # A client where any `http` requests are always redirected to `https`
190
+ transport = httpx.Mounts({
191
+ ' http://' : HTTPSRedirect()
192
+ ' https://' : httpx.HTTPTransport()
193
+ })
194
+ client = httpx.Client(transport = transport)
195
+ ```
196
+
197
+ A useful pattern here is custom transport classes that wrap the default HTTP implementation. For example...
198
+
199
+ ``` python
200
+ class DebuggingTransport (httpx .BaseTransport ):
201
+ def __init__ (self , ** kwargs ):
202
+ self ._wrapper = httpx.HTTPTransport(** kwargs)
203
+
204
+ def handle_request (self , request ):
205
+ print (f " >>> { request} " )
206
+ response = self ._wrapper.handle_request(request)
207
+ print (f " <<< { response} " )
208
+ return response
209
+
210
+ def close (self ):
211
+ self ._wrapper.close()
212
+
213
+ transport = DebuggingTransport()
214
+ client = httpx.Client(transport = transport)
215
+ ```
216
+
217
+ Here's another case, where we're using a round-robin across a number of different proxies...
218
+
219
+ ``` python
220
+ class ProxyRoundRobin (httpx .BaseTransport ):
221
+ def __init__ (self , proxies , ** kwargs ):
222
+ self ._transports = [
223
+ httpx.HTTPTransport(proxy = proxy, ** kwargs)
224
+ for proxy in proxies
225
+ ]
226
+ self ._idx = 0
227
+
228
+ def handle_request (self , request ):
229
+ transport = self ._transports[self ._idx]
230
+ self ._idx = (self ._idx + 1 ) % len (self ._transports)
231
+ return transport.handle_request(request)
232
+
233
+ def close (self ):
234
+ for transport in self ._transports:
235
+ transport.close()
236
+
237
+ proxies = [
238
+ httpx.Proxy(" http://127.0.0.1:8081" ),
239
+ httpx.Proxy(" http://127.0.0.1:8082" ),
240
+ httpx.Proxy(" http://127.0.0.1:8083" ),
241
+ ]
242
+ transport = ProxyRoundRobin(proxies = proxies)
243
+ client = httpx.Client(transport = transport)
191
244
```
192
245
193
246
## Mock transports
0 commit comments