```python
proxies = {
- "http": "http://localhost:8030",
- "https": "http://localhost:8031",
+ "http://": "http://localhost:8030",
+ "https://": "http://localhost:8031",
}
with httpx.Client(proxies=proxies) as client:
For detailed information about proxy routing, see the [Routing](#routing) section.
!!! tip "Gotcha"
- In most cases, the proxy URL for the `https` key _should_ use the `http://` scheme (that's not a typo!).
+ In most cases, the proxy URL for the `https://` key _should_ use the `http://` scheme (that's not a typo!).
This is because HTTP proxying requires initiating a connection with the proxy server. While it's possible that your proxy supports doing it via HTTPS, most proxies only support doing it via HTTP.
```python
proxies = {
- "http": "http://username:password@localhost:8030",
+ "http://": "http://username:password@localhost:8030",
# ...
}
```
HTTPX provides fine-grained controls for deciding which requests should go through a proxy, and which shouldn't. This process is known as proxy routing.
-The `proxies` dictionary maps URL patterns ("proxy keys") to proxy URLs. HTTPX matches requested URLs against proxy keys to decide which proxy should be used, if any. Matching is done from most specific proxy keys (e.g. `https://<domain>:<port>`) to least specific ones (e.g. `https`).
+The `proxies` dictionary maps URL patterns ("proxy keys") to proxy URLs. HTTPX matches requested URLs against proxy keys to decide which proxy should be used, if any. Matching is done from most specific proxy keys (e.g. `https://<domain>:<port>`) to least specific ones (e.g. `https://`).
HTTPX supports routing proxies based on **scheme**, **domain**, **port**, or a combination of these.
```python
proxies = {
- "all": "http://localhost:8030",
+ "all://": "http://localhost:8030",
}
```
```python
proxies = {
- "http": "http://localhost:8030",
- "https": "http://localhost:8031",
+ "http://": "http://localhost:8030",
+ "https://": "http://localhost:8031",
}
```
```python
proxies = {
# Route requests through a proxy by default...
- "all": "http://localhost:8031",
+ "all://": "http://localhost:8031",
# Except those for "example.com".
"all://example.com": None,
}
```python
proxies = {
# Route all traffic through a proxy by default...
- "all": "http://localhost:8030",
+ "all://": "http://localhost:8030",
# But don't use proxies for HTTPS requests to "domain.io"...
"https://domain.io": None,
# And use another proxy for requests to "example.com" and its subdomains...
@pytest.mark.parametrize(
["proxies", "expected_proxies"],
[
- ("http://127.0.0.1", [("all", "http://127.0.0.1")]),
- ({"all": "http://127.0.0.1"}, [("all", "http://127.0.0.1")]),
+ ("http://127.0.0.1", [("all://", "http://127.0.0.1")]),
+ ({"all://": "http://127.0.0.1"}, [("all://", "http://127.0.0.1")]),
(
- {"http": "http://127.0.0.1", "https": "https://127.0.0.1"},
- [("http", "http://127.0.0.1"), ("https", "https://127.0.0.1")],
+ {"http://": "http://127.0.0.1", "https://": "https://127.0.0.1"},
+ [("http://", "http://127.0.0.1"), ("https://", "https://127.0.0.1")],
),
- (httpx.Proxy("http://127.0.0.1"), [("all", "http://127.0.0.1")]),
+ (httpx.Proxy("http://127.0.0.1"), [("all://", "http://127.0.0.1")]),
(
- {"https": httpx.Proxy("https://127.0.0.1"), "all": "http://127.0.0.1"},
- [("all", "http://127.0.0.1"), ("https", "https://127.0.0.1")],
+ {
+ "https://": httpx.Proxy("https://127.0.0.1"),
+ "all://": "http://127.0.0.1",
+ },
+ [("all://", "http://127.0.0.1"), ("https://", "https://127.0.0.1")],
),
],
)
[
("http://example.com", None, None),
("http://example.com", {}, None),
- ("http://example.com", {"https": PROXY_URL}, None),
+ ("http://example.com", {"https://": PROXY_URL}, None),
("http://example.com", {"http://example.net": PROXY_URL}, None),
# Using "*" should match any domain name.
("http://example.com", {"http://*": PROXY_URL}, PROXY_URL),
("http://wwwexample.com", {"http://*example.com": PROXY_URL}, None),
# ...
("http://example.com:443", {"http://example.com": PROXY_URL}, PROXY_URL),
- ("http://example.com", {"all": PROXY_URL}, PROXY_URL),
- ("http://example.com", {"all": PROXY_URL, "http://example.com": None}, None),
- ("http://example.com", {"http": PROXY_URL}, PROXY_URL),
+ ("http://example.com", {"all://": PROXY_URL}, PROXY_URL),
+ ("http://example.com", {"all://": PROXY_URL, "http://example.com": None}, None),
+ ("http://example.com", {"http://": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://example.com": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://example.com:80": PROXY_URL}, None),
("http://example.com", {"http://example.com": PROXY_URL}, PROXY_URL),
(
"http://example.com",
{
- "all": PROXY_URL + ":1",
- "http": PROXY_URL + ":2",
+ "all://": PROXY_URL + ":1",
+ "http://": PROXY_URL + ":2",
"all://example.com": PROXY_URL + ":3",
"http://example.com": PROXY_URL + ":4",
},
(
"http://example.com",
{
- "all": PROXY_URL + ":1",
- "http": PROXY_URL + ":2",
+ "all://": PROXY_URL + ":1",
+ "http://": PROXY_URL + ":2",
"all://example.com": PROXY_URL + ":3",
},
PROXY_URL + ":3",
),
(
"http://example.com",
- {"all": PROXY_URL + ":1", "http": PROXY_URL + ":2"},
+ {"all://": PROXY_URL + ":1", "http://": PROXY_URL + ":2"},
PROXY_URL + ":2",
),
],
@pytest.mark.asyncio
async def test_async_proxy_close():
- client = httpx.AsyncClient(proxies={"all": PROXY_URL})
+ client = httpx.AsyncClient(proxies={"all://": PROXY_URL})
await client.aclose()
def test_sync_proxy_close():
- client = httpx.Client(proxies={"all": PROXY_URL})
+ client = httpx.Client(proxies={"all://": PROXY_URL})
client.close()
assert transport == client._transport
else:
assert transport.proxy_origin == url_to_origin(expected)
+
+
+@pytest.mark.parametrize(
+ ["proxies", "expected_scheme"],
+ [
+ ({"http": "http://127.0.0.1"}, "http://"),
+ ({"https": "http://127.0.0.1"}, "https://"),
+ ({"all": "http://127.0.0.1"}, "all://"),
+ ],
+)
+def test_for_deprecated_proxy_params(proxies, expected_scheme):
+ with pytest.deprecated_call() as block:
+ httpx.AsyncClient(proxies=proxies)
+
+ warning_message = str(block.pop(DeprecationWarning))
+
+ assert expected_scheme in warning_message