Improve 'Custom transports' docs (#3081)
This commit is contained in:
parent
c51af4ba52
commit
3faa4a8f2e
@ -2,7 +2,7 @@ HTTPX's `Client` also accepts a `transport` argument. This argument allows you
|
||||
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
|
||||
@ -83,7 +83,7 @@ with httpx.Client(transport=transport, base_url="http://testserver") as client:
|
||||
...
|
||||
```
|
||||
|
||||
## ASGITransport
|
||||
## ASGI Transport
|
||||
|
||||
You can configure an `httpx` client to call directly into an async Python web application using the ASGI protocol.
|
||||
|
||||
@ -148,7 +148,7 @@ However it is suggested to use `LifespanManager` from [asgi-lifespan](https://gi
|
||||
|
||||
## 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
|
||||
@ -166,28 +166,81 @@ A complete example of a custom transport implementation would be:
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user