ProxyError i Requests mod et privat API? Kontrollér miljøet først
Requests fletter proxy-, auth- og CA-indstillinger fra miljøet. Læs, hvad processen ser, udeluk den private vært, og behold TLS-verifikationen slået til.
VPN er oppe, det interne dashboard åbner i en browser, og Python-scriptet kaster stadig en proxyfejl. Der er intet i vejen med tunnelen i det billede: fortolkeren læser en proxyadresse fra sit eget miljø og sender anmodningen derhen. Denne runbook læser det miljø, processen faktisk ser, anvender den snævreste udelukkelse og overvejer først derefter en eksplicit sessionpolitik. Hvert trin slutter med en kommando, hvis output afgør, om du fortsætter.
Læs det miljø, processen faktisk ser
Proxyindstillinger på skrivebordet, shell-eksporter og Environment=-linjerne i en systemd-unit er tre forskellige kilder, og Requests læser kun den sidste, den arver. Kør diagnosen nedenfor i samme shell, container eller unit, som kører det fejlende script, ikke i din interaktive terminal. En variabel, der er eksporteret i dit login-shell, er usynlig for en containerproces, og det gab forklarer mange rapporter om en proxy, der dukker op fra ingenting. De to kommandoer udskriver de samme data på forskellige detaljeringsniveauer.
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()]"
Begge stavemåder af hver variabel læses, og dubletter anvendes i den rækkefølge, processen modtog dem, så en forældet HTTP_PROXY kan tilsidesætte den værdi, du netop har eksporteret. CA-bundle-variablerne betyder også noget her, fordi de ændrer, hvad verify opløses til, uden at optræde nogen steder i koden. Hvis output er tomt, er miljøet ikke dit problem, og du kan stoppe med at læse dette afsnit. Hvis det viser en proxy, du ikke genkender, skal du finde den fil eller unit, der sætter den, før du ændrer noget.
Spørg Requests, hvad den ville gøre med en bestemt URL. Dette kald viser de sammenflettede proxy-, verify- og cert-værdier for den anmodning uden at sende en pakke.
python3 -c "import requests;s=requests.Session();print(s.merge_environment_settings('https://api.corp.example/status',{},None,None,None))"
En ikke-tom proxies-post for den private vært er dit svar, og den udskrevne verify-værdi fortæller, hvilken CA-bundle anmodningen ville stole på. Hvis begge ser korrekte ud, er fejlen senere i stakken, og du bør springe til verifikationsafsnittet. Gæt ikke ud fra koden: sammenfletningen sker for hver anmodning, og derfor kan én session opføre sig forskelligt for to værter.
Udeluk den private vært, før du deaktiverer noget
Når proxyen virkelig er nødvendig for andre destinationer, er den snævre rettelse en udelukkelse for denne vært. Føj til den eksisterende liste i stedet for at erstatte den, fordi sletning af NO_PROXY ødelægger enhver anden intern destination, der stolede på den. Kommandoerne nedenfor føjer posten til og spørger derefter Requests, om omgåelsen gælder.
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))"
Matchning sker efter værtsuffix, så .corp.example dækker hele domænet, mens api.corp.example dækker ét navn. En bar stjerne deaktiverer proxy for enhver vært og er næsten aldrig det, et produktionsjob ønsker. Om en CIDR-post respekteres, afhænger af Requests- og urllib3-versionerne i imaget, så test den præcise post i stedet for at antage, at den virker. Kontrollér resultatet af should_bypass_proxies for den rigtige URL, ikke for et værtsnavn, du har skrevet fra hukommelsen.
Hold de to lag adskilt i hovedet. At omgå HTTP-proxyen omgår ikke VPN'en, fordi proxybeslutningen træffes i biblioteket, og tunnelbeslutningen træffes i kernens routingtabel.
Deaktiver kun trust_env som en bevidst sessionpolitik
Hvis hele jobbet skal ignorere den omgivende konfiguration, skal du bygge sessionen eksplicit og registrere beslutningen i koden. Det er en politik, ikke en omgåelse, og den hører i en diff, som en anmelder kan se. Eksemplet nedenfor beholder en timeout, en eksplicit CA-sti og et statuscheck.
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()
At slå trust_env fra ændrer tre adfærdsmønstre på én gang, og kun ét af dem handler om proxy. Requests holder op med at læse .netrc-legitimationsoplysninger, og variablene REQUESTS_CA_BUNDLE og CURL_CA_BUNDLE holder op med at påvirke verify, som derefter falder tilbage til det medfølgende certifikatlager. Hvis din organisation afslutter TLS med sin egen CA, giver denne tilbagefaldsløsning en verifikationsfejl, der ser ud til ikke at have noget med den ændring at gøre, du netop har foretaget. Det er den eksplicitte videregivelse af verify, der holder de to effekter adskilt.
Det, du ikke bør gøre, er at sætte verify=False for at dæmpe den resulterende fejl. Det bytter en proxyfejlkonfiguration for en uverificeret forbindelse og skjuler det certifikatproblem, som udelukkelsen skulle afdække.
Verificér det fejlende lag, og behold en tilbagerulning
Tre fejl ser ens ud i en log og har intet til fælles: en proxy, der ikke kan nå destinationen, kaster ProxyError eller returnerer 502, et tillidsproblem kaster SSLError, og en applikationsafvisning returnerer 401 eller 403. Genskab anmodningen uden for Requests for at se, hvilken du har. Kommandoerne nedenfor fjerner proxyen, tester certifikatkæden og gentager derefter kaldet gennem biblioteket.
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)"
Hvis curl-kaldet lykkes, og Python-kaldet fejler, er miljøet stadig forskellen. Hvis begge fejler i TLS-fasen, var proxyen aldrig problemet, og certifikatkæden er det. Hvis begge returnerer 401, nåede anmodningen applikationen, og det resterende arbejde er autentificering. At notere, hvilken af de tre du har observeret, sparer den næste person en time.
Tilbagerulning er én linje i begge retninger: fjern udelukkelsen, eller flip trust_env tilbage. Gem den tidligere NO_PROXY-værdi, før du føjer til den, og foretræk et wrapper-script eller en Environment=-post på unit-niveau frem for en eksport, der kun lever i din terminalhistorik. Begge ændringer er synlige i procesmiljøet, så en genstart bringer dig normalt tilbage til den gamle adfærd.
Afslut med at bekræfte fire ting: de sammenflettede indstillinger for den private URL viser ingen proxy, certifikatet validerer mod den tilsigtede CA, anmodningen returnerer den status, du forventer, og ændringen er committet et sted, der kan genskabes. Et grønt script med et uforklaret miljø er en rettelse, der går i stykker igen på den næste maskine. Kommandoerne i denne runbook er dem, du skal indsætte i billetten.