Chyba ProxyError v Requests u soukromého API? Nejprve zkontrolujte prostředí
Requests slučuje nastavení proxy, ověřování a CA z prostředí. Přečtěte si, co proces vidí, vylučte soukromého hostitele a ponechte ověřování TLS zapnuté.
VPN běží, interní panel se v prohlížeči otevře, a skript v Pythonu přesto hlásí chybu proxy. Na tomto obrázku není s tunelem nic špatně: interpret čte adresu proxy ze svého vlastního prostředí a posílá tam požadavek. Tento runbook čte prostředí, které proces skutečně vidí, uplatní nejužší vyloučení a teprve potom zvažuje výslovnou politiku relace. Každý krok končí příkazem, jehož výstup rozhoduje, zda budete pokračovat.
Přečtěte si prostředí, které proces skutečně vidí
Nastavení proxy na ploše, exporty v shellu a řádky Environment= v unitě systemd jsou tři různé zdroje a Requests čte jen poslední, který zdědí. Spusťte diagnostiku níže ve stejném shellu, kontejneru nebo unitě, který spouští selhávající skript, ne ve svém interaktivním terminálu. Proměnná exportovaná ve vašem přihlašovacím shellu je pro proces v kontejneru neviditelná a tato mezera vysvětluje mnoho hlášení o proxy, která se objeví odnikud. Oba příkazy vypisují stejná data na různé úrovni podrobnosti.
env | grep -i -E 'proxy|requests_ca_bundle|curl_ca_bundle'
python3 -c "import os;[print(k,'=',v) for k,v in sorted(os.environ.items()) if 'proxy' in k.lower()]"
Čtou se oba zápisy každé proměnné a duplicitní položky se uplatní v pořadí, v jakém je proces přijal, takže zastaralá HTTP_PROXY může přebít hodnotu, kterou jste právě exportovali. Proměnné CA bundle tu hrají také roli, protože mění, na co se verify překládá, aniž by se kdekoli v kódu objevily. Pokud je výstup prázdný, prostředí není váš problém a můžete přestat číst tuto část. Pokud vypisuje proxy, kterou neznáte, najděte soubor nebo unit, který ji nastavuje, než cokoli změníte.
Zeptejte se Requestsu, co by udělal s konkrétní URL. Toto volání zobrazí sloučené hodnoty proxy, verify a cert pro daný požadavek, aniž by odeslalo paket.
python3 -c "import requests;s=requests.Session();print(s.merge_environment_settings('https://api.corp.example/status',{},None,None,None))"
Neprázdná položka proxies pro soukromého hostitele je vaše odpověď a vypsaná hodnota verify říká, kterému CA bundle by požadavek věřil. Pokud obojí vypadá správně, selhání je dál v zásobníku a měli byste přejít k části o ověřování. Nehádejte z kódu: slučování probíhá pro každý požadavek, proto se jedna relace může chovat různě pro dva hostitele.
Vylučte soukromého hostitele, než cokoli vypnete
Když je proxy skutečně potřeba pro jiné cíle, úzkým řešením je vyloučení tohoto hostitele. Přidávejte do stávajícího seznamu, místo abyste ho nahradili, protože smazání NO_PROXY rozbije každý další interní cíl, který na něm závisel. Příkazy níže položku přidají a poté se Requestsu zeptají, zda se obejití uplatní.
export NO_PROXY="${NO_PROXY:+$NO_PROXY,}api.corp.example,.corp.example"
python3 -c "import requests;print(requests.utils.should_bypass_proxies('https://api.corp.example/status',None))"
Shoda je podle přípony hostitele, takže .corp.example pokrývá celou doménu, zatímco api.corp.example jedno jméno. Samotná hvězdička vypne proxy pro každého hostitele a téměř nikdy to není to, co produkční úloha chce. Zda bude položka CIDR respektována, závisí na verzích Requestsu a urllib3 v image, takže otestujte přesnou položku, místo abyste předpokládali, že funguje. Zkontrolujte výsledek should_bypass_proxies pro skutečnou URL, ne pro jméno hostitele, které jste napsali po paměti.
Držte obě vrstvy v hlavě oddělené. Obcházení HTTP proxy neobchází VPN, protože rozhodnutí o proxy probíhá v knihovně a rozhodnutí o tunelu v jádrové směrovací tabulce.
Vypínejte trust_env jen jako záměrnou politiku relace
Pokud má celá úloha ignorovat okolní konfiguraci, sestavte relaci explicitně a rozhodnutí zaznamenejte v kódu. To je politika, ne obchvat, a patří do diffu, který recenzent uvidí. Příklad níže zachovává timeout, explicitní cestu k CA a kontrolu stavu.
import requests
with requests.Session() as session:
session.trust_env = False
response = session.get(
"https://api.corp.example/status",
timeout=(5, 20),
verify="/etc/ssl/certs/corp-ca.pem",
)
response.raise_for_status()
Vypnutí trust_env mění tři chování najednou a jen jedno z nich se týká proxy. Requests přestane číst přihlašovací údaje z .netrc a proměnné REQUESTS_CA_BUNDLE a CURL_CA_BUNDLE přestanou ovlivňovat verify, které se pak vrátí k vestavěnému úložišti certifikátů. Pokud vaše organizace ukončuje TLS vlastní CA, toto vrácení vyvolá chybu ověření, která vypadá nesouvisející se změnou, kterou jste právě provedli. Právě výslovné předání verify drží oba efekty oddělené.
Co byste dělat neměli, je nastavit verify=False, abyste výslednou chybu umlčeli. To vymění špatnou konfiguraci proxy za neověřené spojení a skryje problém s certifikátem, který mělo vyloučení odhalit.
Ověřte selhávající vrstvu a ponechte si možnost vrácení
Tři poruchy vypadají v logu stejně a nemají nic společného: proxy, která nedosáhne cíle, vyvolá ProxyError nebo vrátí 502, problém s důvěrou vyvolá SSLError a odmítnutí aplikace vrátí 401 nebo 403. Reprodukujte požadavek mimo Requests, abyste zjistili, kterou máte. Příkazy níže odstraní proxy, otestují řetěz certifikátů a poté volání zopakují přes knihovnu.
curl -sv --noproxy '*' https://api.corp.example/status -o /dev/null
openssl s_client -connect api.corp.example:443 -servername api.corp.example </dev/null
python3 -c "import requests;r=requests.get('https://api.corp.example/status',timeout=10);print(r.status_code)"
Pokud volání curl uspěje a volání v Pythonu selže, rozdílem je stále prostředí. Pokud obě selžou ve fázi TLS, proxy nikdy nebyla problémem a problémem je řetěz certifikátů. Pokud obě vrátí 401, požadavek se dostal do aplikace a zbývající prací je autentizace. Zaznamenání, kterou ze tří jste pozorovali, ušetří dalšímu člověku hodinu.
Vrácení je jeden řádek oběma směry: odstraňte vyloučení, nebo přepněte trust_env zpět. Uložte předchozí hodnotu NO_PROXY, než k ní něco přidáte, a dejte přednost obalovému skriptu nebo položce Environment= na úrovni unity před exportem, který žije jen v historii vašeho terminálu. Obě změny jsou viditelné v prostředí procesu, takže restart vás obvykle vrátí ke starému chování.
Skončete potvrzením čtyř věcí: sloučené nastavení pro soukromou URL neukazuje žádnou proxy, certifikát se ověřuje proti zamýšlené CA, požadavek vrací stav, který očekáváte, a změna je commitnutá na místě, které lze reprodukovat. Zelený skript s nevysvětleným prostředím je oprava, která se na dalším stroji znovu rozbije. Příkazy v tomto runbooku jsou ty, které vložíte do tiketu.