to provide a custom Transport object that will be used to perform the actual
sending of the requests.
-## HTTPTransport
+## HTTP Transport
For some advanced configuration you might need to instantiate a transport
class directly, and pass it to the client instance. One example is the
...
```
-## ASGITransport
+## ASGI Transport
You can configure an `httpx` client to call directly into an async Python web application using the ASGI protocol.
## Custom transports
-A transport instance must implement the low-level Transport API, which deals
+A transport instance must implement the low-level Transport API which deals
with sending a single request, and returning a response. You should either
subclass `httpx.BaseTransport` to implement a transport to use with `Client`,
or subclass `httpx.AsyncBaseTransport` to implement a transport to
import json
import httpx
-
class HelloWorldTransport(httpx.BaseTransport):
"""
A mock transport that always returns a JSON "Hello, world!" response.
"""
def handle_request(self, request):
- message = {"text": "Hello, world!"}
- content = json.dumps(message).encode("utf-8")
- stream = httpx.ByteStream(content)
- headers = [(b"content-type", b"application/json")]
- return httpx.Response(200, headers=headers, stream=stream)
+ return httpx.Response(200, json={"text": "Hello, world!"})
```
-Which we can use in the same way:
+Or this example, which uses a custom transport and `httpx.Mounts` to always redirect `http://` requests.
-```pycon
->>> import httpx
->>> client = httpx.Client(transport=HelloWorldTransport())
->>> response = client.get("https://example.org/")
->>> response.json()
-{"text": "Hello, world!"}
+```python
+class HTTPSRedirect(httpx.BaseTransport):
+ """
+ A transport that always redirects to HTTPS.
+ """
+ def handle_request(self, request):
+ url = request.url.copy_with(scheme="https")
+ return httpx.Response(303, headers={"Location": str(url)})
+
+# A client where any `http` requests are always redirected to `https`
+transport = httpx.Mounts({
+ 'http://': HTTPSRedirect()
+ 'https://': httpx.HTTPTransport()
+})
+client = httpx.Client(transport=transport)
+```
+
+A useful pattern here is custom transport classes that wrap the default HTTP implementation. For example...
+
+```python
+class DebuggingTransport(httpx.BaseTransport):
+ def __init__(self, **kwargs):
+ self._wrapper = httpx.HTTPTransport(**kwargs)
+
+ def handle_request(self, request):
+ print(f">>> {request}")
+ response = self._wrapper.handle_request(request)
+ print(f"<<< {response}")
+ return response
+
+ def close(self):
+ self._wrapper.close()
+
+transport = DebuggingTransport()
+client = httpx.Client(transport=transport)
+```
+
+Here's another case, where we're using a round-robin across a number of different proxies...
+
+```python
+class ProxyRoundRobin(httpx.BaseTransport):
+ def __init__(self, proxies, **kwargs):
+ self._transports = [
+ httpx.HTTPTransport(proxy=proxy, **kwargs)
+ for proxy in proxies
+ ]
+ self._idx = 0
+
+ def handle_request(self, request):
+ transport = self._transports[self._idx]
+ self._idx = (self._idx + 1) % len(self._transports)
+ return transport.handle_request(request)
+
+ def close(self):
+ for transport in self._transports:
+ transport.close()
+
+proxies = [
+ httpx.Proxy("http://127.0.0.1:8081"),
+ httpx.Proxy("http://127.0.0.1:8082"),
+ httpx.Proxy("http://127.0.0.1:8083"),
+]
+transport = ProxyRoundRobin(proxies=proxies)
+client = httpx.Client(transport=transport)
```
## Mock transports