Konfiguracja proxy w HTTPX: uwierzytelnianie, środowisko i limity czasu

10 min

Ustawić proxy w HTTPX przez proxy=, przekazać dane logowania, utrzymać HTTPS na CONNECT i odróżnić domyślne zmienne środowiska od jawnych mounts i limitów czasu.

Ten poradnik jest dla programistów Pythona, którzy potrzebują, żeby HTTPX 0.28.1 wychodził przez proxy HTTP albo SOCKS5. Prywatne sprawdzenia redakcyjne używały origin na loopback i atrapy proxy CONNECT, nie konta u dostawcy. Nie ma darmowych kluczy, a Top Proxy nie sprzedaje adresów IP. Te sprawdzenia dowodzą wyłącznie laboratoryjnej trasy. To nie jest publiczny plik do pobrania.

01Skierować żądanie przez proxy=

Zainstalowany klient przyjmuje proxy= na httpx.get i na httpx.Client. Starszy HTTPX przyjmował też mapowanie proxies= ze wzorców URL na URL proxy. To był sam HTTPX, nie słownik wyłącznie z Requests. HTTPX 0.28.0 (28 listopada 2024) usunął przestarzały argument proxies. Ten przewodnik zostaje przy 0.28.1 proxy= i mounts=. Forma jednego proxy to ciąg URL albo obiekt httpx.Proxy.

Proxy HTTP (dostęp 14 października 2026) mówi, że ten URL podaje się przy inicjalizacji klienta albo na pomocnikach najwyższego poziomu. Pojedyncze proxy="http://127.0.0.1:PORT" wysyła przez ten przeskok zarówno HTTP, jak i HTTPS. HTTPS nie potrzebuje URL proxy https://. Schemat celu i schemat proxy to różne pokrętła.

  1. Przypiąć klienta, który naprawdę będzie importowany. Ten przewodnik używał HTTPX 0.28.1, httpcore 1.0.9 i Pythona 3.14.6.
  2. Zbudować Client z proxy= ustawionym na URL proxy HTTP. Na czas dowodu jawnej ścieżki zostawić trust_env=False, żeby pozostałe zmienne powłoki nie ukradły trasy.
  3. Pobrać origin HTTP, nad którym jest kontrola. Czytać log proxy, nie tylko kod statusu. Laboratoryjny atrapowy forwarder zapisał GET http://httpx-lab.origin:<port>/ z authorized: true.
  4. Zamknąć klienta menedżerem kontekstu. To zamyka pulę transportu. Zapomniany klient to wyciek gniazda, nie szybszy skrypt.

Bezpośrednia linia bazowa ma znaczenie. Po wyczyszczeniu HTTP_PROXY, HTTPS_PROXY, ALL_PROXY i NO_PROXY w procesie potomnym klient bez proxy= trafił w origin HTTP, a atrapa proxy pozostała bezczynna. To kontrola bez proxy. Nie mówi, co HTTPX zrobiłby, gdyby te zmienne nadal były ustawione. To przyjdzie później.

Jeśli potrzeba dwóch wyjść, nie należy wpychać dwóch URL do proxy=. Użyć mounts z HTTPTransport(proxy=...) na wzorzec i położyć verify, trust_env oraz retries na każdym transporcie. Argument verify= na poziomie klienta w tej kompilacji nie został przekazany na transporty. Mount, który tylko odziedziczył Client(verify=ctx), oblał TLS z ConnectError / SSLCertVerificationError: unable to get local issuer certificate. To samo żądanie przeszło, gdy sam transport dostał verify=ctx.

02Wybrać proxy HTTP dla celu HTTPS

Ludzie nazywają to „proxy HTTPS”, bo witryna jest https://. Przeskok z przodu nadal jest proxy HTTP, które mówi CONNECT. Dokumentacja nazywa to pułapką: klucz https:// w słowniku mounts to schemat celu, a URL proxy przed nim zwykle jest http://.

Przekazywanie i tunelowanie to nie ten sam mechanizm. Dla http:// proxy wykonuje żądanie origin i zwraca bajty origin. Dla https:// klient wysyła CONNECT host:443, proxy otwiera TCP, a TLS idzie między klientem a origin przez ten tunel. Fałszywe 200 z CONNECT bez działającego tunelu bajtów to nie proxy HTTPS. Laboratorium przekazywało prawdziwe ciała origin na HTTP i prawdziwe bajty TLS po CONNECT.

  1. Zostawić URL proxy na http://127.0.0.1:<port> nawet wtedy, gdy cel to https://httpx-lab.origin:<port>/.
  2. Zaufać origin przez ssl.create_default_context(cafile=ca.pem) i przekazać ten kontekst jako verify=. Nie wyłączać weryfikacji.
  3. Potwierdzić, że log proxy pokazuje CONNECT httpx-lab.origin:<https-port>, zanim świętuje się 200.
  4. Powtórzyć raz z domyślnym magazynem CA i bez laboratoryjnego CA. Potrzebna jest awaria TLS, która mimo to zapisała CONNECT.

Ten ostatni krok operatorzy pomijają. W tym przebiegu CONNECT się udał, a potem HTTPX rzucił ConnectError opakowujący SSLCertVerificationError: unable to get local issuer certificate. Tunel był w porządku. Certyfikat nie. Strona Jaki jest mój adres IP w przeglądarce pokazałaby wyjście przeglądarki, nie tego klienta. Sprawdzanie proxy pokazuje, czy host odpowiada HTTP albo SOCKS5, zanim skieruje się na niego HTTPX.

SOCKS5 to trzecia ścieżka. pip install httpx[socks] pociągnęło socksio 1.0.0. httpx.Proxy w 0.28.1 przyjmuje socks5 i socks5h. Wobec kontrolowanego stanowiska SOCKS5 socks5://127.0.0.1:<port> do http://127.0.0.1:<origin>/ wysłało ATYP ipv4. Ten sam klient z socks5h:// i celem-nazwą hosta wysłał ATYP domain httpx-lab.origin. Użycie socks5:// z tą nazwą hosta też wysłało ATYP domain. Ta kompilacja nie rozwiązywała nazwy hosta lokalnie, a potem nie wysyłała adresu IPv4 tak, jak robią to niektóre konfiguracje curl socks5. Nie należy kopiować folkloru socks5h z Requests do HTTPX. Trzeba zmierzyć handshake.

03Ustawić uwierzytelnianie proxy

Dane logowania proxy to nie auth=. auth= to uwierzytelnianie origin. Pomieszanie ich oznacza godzinę debugowania złego przeskoku.

Strona o proxy kładzie userinfo w URL proxy. API dokumentuje też httpx.Proxy(url, auth=(user, password)). Oba zadziałały w laboratorium. Hasło atrapy zawierało @, :, /, # i %. Te znaki należą do userinfo dopiero po kodowaniu URL składnik po składniku albo do krotki auth= na Proxy, która nigdy nie idzie przez parser URL. Logi i rysunki redagowały wartość. Przy debugowaniu nie należy wypisywać Proxy-Authorization.

Brak danych i złe dane to nie jedno zachowanie.

Przy przekazywaniu HTTP żądanie bez użytkownika proxy zwróciło HTTP 407 ze stanowiska. HTTPX pokazał to jako status_code == 407. Złe hasło dało to samo. Stanowisko zapisało authReason: missing i authReason: wrong. Bez wyjątku. Jeśli wrapper później rzuca, należy zachować 407.

Przy HTTPS CONNECT te same brakujące albo złe dane atrapy rzuciły httpx.ProxyError z komunikatem 407 Proxy Authentication Required. Nie było obiektu odpowiedzi do odczytu. CONNECT to zestawianie tunelu. 407 tam to awaria transportu, nie strona origin.

Poprawne dane zwróciły origin 200 na obu ścieżkach. Origin nigdy nie zobaczył Proxy-Authorization. Ten nagłówek zostaje na przeskoku proxy. Jeśli potrzeba też origin Basic, wysłać auth=(origin_user, origin_pass) na kliencie. Laboratoryjna trasa /origin-auth zwróciła 401 bez tego i 200, gdy oba przeskoki były uwierzytelnione.

  1. Użytkownika i hasło proxy kłaść w httpx.Proxy(..., auth=(user, password)), gdy hasło ma znaki zastrzeżone.
  2. Origin auth= zostawić dla witryny, nie dla proxy.
  3. HTTP 407 i CONNECT ProxyError traktować jako różne wyniki. Zapisać klasę, którą faktycznie złapano.
  4. Odrzucić myśl, że „działa w curl” dowodzi, iż HTTPX wysłał ten sam nagłówek. Trzeba to udowodnić na tym kliencie.

Produkty rezydenckie dokumentują ten sam podział. Oxylabs Residential Proxies (dostęp 14 października 2026) wymienia HTTP, HTTPS, HTTP/3 i SOCKS5, z nazwą użytkownika i hasłem albo listą dozwolonych IP, oraz wejście pr.oxylabs.io:7777 w formie customer-USERNAME:PASSWORD. To udokumentowany kształt punktu końcowego, nie test ich puli. Szybki start rezydencki Decodo (tego samego dnia) pokazuje gate.decodo.com:7000 i mapowanie Pythona, które wysyła zarówno http, jak i https przez jeden URL proxy HTTP. Angielski katalog nadal listuje ten produkt jako smartproxy-com. Publiczna nazwa w dokumentacji to Decodo. Ścieżka się nie zmieniła.

04Zrozumieć domyślne środowisko i mounts

HTTPX domyślnie czyta środowisko. Zmienne środowiska (dostęp 14 października 2026) wymieniają HTTP_PROXY, HTTPS_PROXY, ALL_PROXY i NO_PROXY, plus SSL_CERT_FILE i SSL_CERT_DIR. trust_env=False wyłącza cały ten zestaw. Nie znaczy „pominąć sprawdzenia certyfikatów”.

Proces potomny laboratorium startował z tymi zmiennymi usuniętymi, plus pozostałościami CGI, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE i SSLKEYLOGFILE. Używał pustego prywatnego pliku NETRC. HOME stacji roboczej zostawiono w spokoju. Każdy eksperyment środowiskowy startował z tej linii bazowej i wstrzykiwał tylko nazwane wartości atrap.

Ominięcie loopback wprowadzi w błąd. Klienci HTTP często pomijają 127.0.0.1. Przypadki proxy ze środowiska używały nazwy hosta httpx-lab.origin i NO_PROXY="", z ograniczoną łatą getaddrinfo, która mapuje tę nazwę na loopback. Ta łata to wstrzyknięte zachowanie resolwera. To nie pomiar publicznego DNS.

  1. Wyeksportować HTTP_PROXY i HTTPS_PROXY na zakodowany URL proxy. Ustawić NO_PROXY na pusty ciąg, gdy cel musi iść przez proxy.
  2. Zbudować Client(trust_env=True) bez argumentu proxy=. Żądanie laboratoryjne zwróciło 200 i tylko proxy alpha zapisało GET. Proxy bravo pozostało bezczynne.
  3. Powtórzyć z NO_PROXY=httpx-lab.origin. Origin nadal zwrócił 200. Alpha nie zobaczyło tego GET. To ominięcie i to osobny przypadek, nie efekt uboczny, który się zakłada.
  4. Powtórzyć z tymi samymi zmiennymi i trust_env=False. Żądanie poszło bezpośrednio. Alpha nic nie zobaczyło.

Jawne proxy= wygrało ze sprzecznym środowiskiem. Przy alpha w HTTP_PROXY i proxy= wskazującym na bravo GET dostało bravo, a alpha nie. Sam status 200 nie powiedziałby, który przeskok został użyty. Dwie instrumentowane tożsamości tak.

trust_env=False zatrzymało też zamianę SSL_CERT_FILE w magazyn CA klienta. Przy laboratoryjnym CA w SSL_CERT_FILE i trust_env=True HTTPS do laboratoryjnego origin zwrócił 200. Przy trust_env=False i domyślnym verify=True ten sam URL rzucił ConnectError / SSLCertVerificationError. Podanie verify=ssl.create_default_context(cafile=ca.pem) na tym kliencie z trust_env=False przywróciło 200. Weryfikacja pozostała włączona. Zniknęło tylko wyszukiwanie w środowisku.

transport= i mounts= to różne argumenty konstruktora. HTTPX 0.28.1 ustawia allow_env_proxies = trust_env and transport is None. Własny obiekt transport= pomija mounts proxy ze środowiska. Słownik mounts= nie. Klient najpierw buduje mounts ze środowiska, potem aktualizuje tę mapę własnymi mounts. Bardziej szczegółowe wzorce URL wygrywają. http:// z HTTP_PROXY pokonuje all://, więc Client(mounts={"all://": some_transport}, trust_env=True) nadal może wysłać cele HTTP przez odziedziczone proxy. Ustawić trust_env=False, gdy routing ze środowiska ma być wyłączony. proxy= i verify= kłaść na każdym zamontowanym HTTPTransport. verify= na poziomie klienta nadal nie kopiuje się na te transporty. Ta ostatnia pomyłka to sposób, w jaki wraca awaria niezaufanego CA.

05Przetestować cykl życia sync i async

Sync i async to dwa klienty. Dzielą kształt proxy=. Nie dzielą puli połączeń.

with httpx.Client(proxy=..., verify=ctx) as client: to forma sync. Zamknięcie następuje przy wyjściu z kontekstu. async with httpx.AsyncClient(proxy=..., verify=ctx) as client: to forma async. Wywołuje się await client.get(...). Mieszanie get bez await wewnątrz klienta async to błąd, nie limit czasu.

Przypadek async w tym laboratorium używał AsyncClient z tym samym URL proxy HTTP i laboratoryjnym kontekstem SSL. await client.get(https_url) zwróciło 200 ze znacznikiem origin HTTPS. Proxy zapisało CONNECT. To jeden udany tunel async. To nie benchmark współbieżności i nic nie mówi o ponownym użyciu puli pod obciążeniem.

Zamontowane transporty potrzebują tej samej ścieżki zamknięcia. HTTPTransport utworzony ręcznie zamyka klient, jeśli klient nim włada przez mounts. Jeśli zmienna transportu żyje między klientami, w finally wywołać transport.close(). Laboratorium robiło to w przypadkach ponowień i mounts.

Ponowienia należą do transportu. Transporty (dostęp 14 października 2026) mówią, że HTTPTransport(retries=...) ponawia ConnectError i ConnectTimeout. Nie ponawia 429 ani 503. Laboratorium ustawiło retries=2 i pobrało /status/503. Origin policzył jedno trafienie. HTTPX zwrócił 503. To nie urllib3 Retry. Nie należy wklejać folkloru allowed_methods do HTTPX.

06Diagnozować awarie połączenia, odczytu ciała i TLS

Nazwać złapany wyjątek. HTTPX ma prawdziwą hierarchię. Spłaszczenie wszystkiego do „błędu proxy” ukrywa przeskok, który zawiódł.

Zamknięty listener na loopback dał ConnectError opakowujący ConnectionRefusedError: [Errno 61] Connection refused. To odmowa. To nie limit czasu połączenia. Na tym jądrze Darwin gniazdo, które było zbindowane i trzymane, ale nigdy nie weszło w listen, nie odmawiało. HTTPX rzucił ConnectTimeout opakowujący TimeoutError po skonfigurowanym terminie połączenia. To oczekiwanie jest oznaczone jako zachowanie wstrzykniętego stanowiska dla bind-without-listen. To nie pomiar publicznego internetu.

Limity czasu odczytu dotyczą kawałków po starcie odpowiedzi. Origin /slow-body wysłało kompletne nagłówki natychmiast, zapisało i wypchnęło jeden bajt ciała, a potem czekało dłużej niż Timeout(read=0.45). Przy strumieniowaniu ciała HTTPX zwrócił status 200, odpaliło się zdarzenie pierwszego bajtu, przyszedł jeden bajt, a potem ReadTimeout opakowujący TimeoutError. Nagłówki już wylądowały. ConnectError byłby złą klasą. ConnectTimeout byłby złą klasą. Jeśli wywołuje się tylko response.text bez strumieniowania, i tak nastąpi timeout, ale znika dowód, że nagłówki doszły.

Awarie TLS po CONNECT pozostały ConnectError z SSLCertVerificationError. Proxy już przyjęło tunel. Wyłączenie verify=False by to ukryło. Nie należy.

Użyć proxy mobilnych albo proxy rezydenckich, gdy zadaniem jest wyjście przypisane przez ISP. Obsługa protokołu i pochodzenie IP to różne wymiary. To laboratorium nigdy nie twierdziło kraju, wskaźnika sukcesu ani konta.

AwariaCo rzuciło laboratorium 0.28.1Czym to nie jest
Proxy HTTP, brakujący albo zły BasicStatus odpowiedzi 407Wyjątek CONNECT
HTTPS CONNECT, brakujący albo zły BasicProxyError („407 Proxy Authentication Required”)Strona origin 407
Laboratoryjny HTTPS bez laboratoryjnego CAConnectError / SSLCertVerificationError po CONNECTDowód, że CONNECT nigdy nie nastąpił
Zamknięty port loopbackConnectError / ConnectionRefusedErrorConnectTimeout
Bind bez listen na DarwinConnectTimeout (oczekiwanie specyficzne dla stanowiska)Odmowa albo RTT WAN
Opóźnione ciało po pierwszym bajcieReadTimeout przy iteracji iter_bytes()Awaria połączenia
Origin /status/503 z retries=2Status 503, jedno trafienie originPonowienie aplikacyjne
Tabela asercji z laboratorium HTTPX 0.28.1 na loopback z 14 października 2026

Rysunek to tabela asercji z tego przebiegu. To nie obraz okładki i nie zrzut interfejsu sprawdzania.

Następny blok to schematyczny szkic API. Porty, ścieżka CA i hasło to placeholdery, które zastępuje się wartościami pod własną kontrolą. To nie publiczny pakiet stanowiska i nie uruchomi się z pustego katalogu.

import httpx
import ssl

# PLACEHOLDERS. Do not treat these literals as lab values.
ctx = ssl.create_default_context(cafile="PATH/TO/LAB_CA.pem")
proxy = httpx.Proxy(
    "http://127.0.0.1:PROXY_PORT",
    auth=("PROXY_USER", "PROXY_PASSWORD"),
)
timeout = httpx.Timeout(5.0, connect=2.0, read=0.45)

with httpx.Client(proxy=proxy, verify=ctx, trust_env=False, timeout=timeout) as client:
    http_response = client.get("http://TARGET_HOST:HTTP_PORT/")
    https_response = client.get("https://TARGET_HOST:HTTPS_PORT/")

Klasy wyjątków 0.28.1 oraz wyniki CONNECT kontra 407 w tym artykule pochodzą z prywatnego stanowiska redakcyjnego. Tego stanowiska tu nie publikujemy. Zainstalować klienta, który da się zaimportować przez python -m pip install "httpx[socks]==0.28.1", zależnego od httpcore 1.* i, dla SOCKS, socksio. Host, port i dane logowania proxy HTTP wstawić w placeholdery, używając httpx.Proxy(..., auth=(user, password)), gdy hasło ma znaki zastrzeżone. URL HTTP skierować na origin pod kontrolą dla przekazywania, a URL HTTPS na origin pod kontrolą dla CONNECT, a potem TLS. Dla HTTPS podać verify= jako ssl.create_default_context(cafile=...) z plikiem CA, któremu już się ufa dla tego origin. Zostawić trust_env=False, dopóki dowodzi się jawnej ścieżki proxy=. Nie ustawiać verify=False.

07Wybrać udokumentowany punkt końcowy

Gdy ścieżka klienta jest uczciwa, wybrać host wejścia, który dokumentuje przekazywanie HTTP i CONNECT. Angielskie strony katalogu Oxylabs i Decodo (nadal listowane jako smartproxy-com) 14 października 2026 zwracały żywe samokanoniczne URL. Oficjalna dokumentacja opisuje bramy HTTP z nazwą użytkownika i hasłem albo dozwolonym IP. To dopasowanie punktu końcowego na papierze. Ten artykuł nie logował się do żadnego z tych produktów i ich nie rankinguje.

Oxylabs — proxy rezydenckie i datacenter
Oxylabs — proxy rezydenckie i datacenter4.0771

Oxylabs sprzedaje proxy rezydenckie, mobilne, ISP i datacenter w jednej subskrypcji miesięcznej od $30. Płatności: karty, przelew, AliPay, PayPal.

10 krajów
0,45 USD
za 1 GB
Decodo (Smartproxy) — proxy rezydenckie i datacenter
Decodo (Smartproxy) — proxy rezydenckie i datacenter4.22118

Decodo (dawniej Smartproxy) sprzedaje proxy rezydenckie i datacenter. Rezydenckie: $4/GB bez planu miesięcznego albo pakiety miesięczne od $3.75/GB za 3 GB. Płatności: karty, PayPal, Alipay, Google/Apple Pay, krypto (z ograniczeniami).

83 kraje
0,38 USD
za 1 GB

Jeśli potrzebne było tylko potwierdzenie w przeglądarce, zostać przy Jaki jest mój adres IP. Jeśli potrzebny był HTTPX, wierzyć logowi proxy i klasie wyjątku z tej biblioteki. Te dwa rozjeżdżają się częściej, niż przyznają wpisy na blogach.

Jak ustawić proxy w HTTPX?

Przekazać proxy= do httpx.Client albo httpx.get. Użyć ciągu URL albo httpx.Proxy. HTTPX 0.28.1 nie ma argumentu proxies=. HTTPX usunął to przestarzałe mapowanie w 0.28.0. Do routingu per schemat montować obiekty HTTPTransport, z których każdy dostaje własne argumenty proxy i verify. mounts= nadal scala wzorce ze środowiska, gdy trust_env=True. Użyć transport= albo trust_env=False, gdy odziedziczone HTTP_PROXY nie ma obowiązywać.

Po co http:// dla proxy obsługującego HTTPS?

Przeskok proxy zwykle jest zwykłym HTTP. Cele HTTPS używają CONNECT przez ten przeskok, a potem TLS do origin. Klucz https:// w mounts to schemat celu. URL proxy przed nim zostaje http://, chyba że produkt naprawdę mówi TLS do samego proxy.

Czym dane logowania proxy różnią się od auth=?

Userinfo proxy albo httpx.Proxy(auth=(user, password)) wysyłają Proxy-Authorization do proxy. auth= to uwierzytelnianie origin. Laboratorium zwracało proxy 407 albo ProxyError przy złych danych proxy i origin 401, gdy brakowało tylko danych origin.

Czy trust_env=False wyłącza weryfikację certyfikatów?

Nie. trust_env=False sprawia, że HTTPX przestaje czytać HTTP_PROXY, NO_PROXY, SSL_CERT_FILE i SSL_CERT_DIR. Weryfikacja TLS zostaje włączona. HTTPX nie ładuje danych origin z netrc, bo trust_env jest true. Jeśli samemu przekaże się httpx.NetRCAuth, to uwierzytelnianie nadal działa przy trust_env=False. Przekazać ssl.create_default_context(cafile=...) jako verify=, gdy potrzeba prywatnego CA. verify=False nie jest przełącznikiem obsługi środowiska.

Dlaczego klient rzuca ReadTimeout po nadejściu nagłówków?

Limit czasu odczytu to termin ciała na kawałek. Laboratoryjny origin wysłał nagłówki i jeden bajt ciała, a potem przerwał. Strumieniowanie zwróciło status 200, dostarczyło ten bajt, a potem rzuciło ReadTimeout. To nie ConnectTimeout i nie awaria rozmowy z proxy.

Czy HTTPTransport ponawia 429 albo 503?

Nie. retries na HTTPTransport ponawia tylko ConnectError i ConnectTimeout. Przy retries=2 laboratoryjny origin /status/503 został trafiony raz, a HTTPX zwrócił 503. Do ponowień statusu potrzeba innej biblioteki.