ProxyError ng Requests sa isang pribadong API? Suriin muna ang kapaligiran
Pinagsasama ng Requests ang proxy, auth at CA settings mula sa kapaligiran. Basahin kung ano ang nakikita ng proseso, ibukod ang pribadong host at panatilihing naka-on ang TLS verification.
Naka-on ang VPN, bumubukas ang panloob na dashboard sa browser, at nagbabalik pa rin ng proxy error ang Python script. Wala namang mali sa tunnel sa larawang iyon: binabasa ng interpreter ang isang proxy address mula sa sarili nitong kapaligiran at doon ipinapadala ang kahilingan. Binabasa ng runbook na ito ang kapaligirang aktwal na nakikita ng proseso, inilalapat ang pinakamakitid na pagbubukod at pagkatapos lang isinasaalang-alang ang tahasang patakaran ng sesyon. Nagtatapos ang bawat hakbang sa isang utos na ang output ang magpapasya kung magpapatuloy ka.
Basahin ang kapaligirang aktwal na nakikita ng proseso
Ang mga setting ng proxy sa desktop, mga export sa shell at mga linya ng Environment= ng isang systemd unit ay tatlong magkaibang pinagmulan, at ang Requests ay binabasa lamang ang huling minana nito. Patakbuhin ang diagnostic sa ibaba sa parehong shell, container o unit na nagpapatakbo ng nabibigong script, hindi sa iyong interactive na terminal. Ang isang variable na na-export sa iyong login shell ay hindi nakikita ng isang container na proseso, at ang puwang na iyon ang nagpapaliwanag ng maraming ulat tungkol sa proxy na lumilitaw mula sa wala. Pareho ang data na ipinapakita ng dalawang utos sa magkaibang antas ng detalye.
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()]"
Binabasa ang parehong baybay ng bawat variable, at ang mga doble na entry ay inilalapat sa pagkakasunod-sunod na natanggap ng proseso, kaya ang lumang HTTP_PROXY ay maaaring mangibabaw sa value na ini-export mo lang. Mahalaga rin dito ang mga variable ng CA bundle, dahil binabago nila kung saan nireresolba ang verify nang hindi lumilitaw kahit saan sa code. Kung walang output, hindi kapaligiran ang problema mo at maaari mong itigil ang pagbasa ng seksyong ito. Kung naglilista ito ng proxy na hindi mo kilala, hanapin ang file o unit na nagtatakda nito bago magbago ng kahit ano.
Tanungin ang Requests kung ano ang gagawin nito sa isang partikular na URL. Ipinapakita ng tawag na ito ang pinagsamang proxy, verify at cert na halaga para sa kahilingang iyon nang hindi nagpapadala ng packet.
python3 -c "import requests;s=requests.Session();print(s.merge_environment_settings('https://api.corp.example/status',{},None,None,None))"
Ang hindi walang laman na entry na proxies para sa pribadong host ang iyong sagot, at ang nakalimbag na halaga ng verify ay nagsasabi kung aling CA bundle ang pagtitiwalaan ng kahilingan. Kung mukhang tama ang dalawa, mas malalim ang pagkasira sa stack at dapat kang tumalon sa seksyon ng verification. Huwag manghula mula sa code: nangyayari ang pagsasama sa bawat kahilingan, kaya maaaring iba ang kilos ng isang sesyon para sa dalawang host.
Ibukod ang pribadong host bago mo i-off ang anuman
Kapag talagang kailangan ang proxy para sa ibang destinasyon, ang makitid na pagwawasto ay isang pagbubukod para sa host na ito. Idagdag sa umiiral na listahan sa halip na palitan ito, dahil sinisira ng pagbura ng NO_PROXY ang bawat iba pang panloob na destinasyon na umasa dito. Idinadagdag ng mga utos sa ibaba ang entry at pagkatapos ay tinatanong ang Requests kung nalalapat ang bypass.
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))"
Ang pagtutugma ay ayon sa suffix ng host, kaya sinasaklaw ng .corp.example ang buong domain habang ang api.corp.example ay isang pangalan lang. Ang hubad na asterisk ay nagpapahina ng proxy para sa bawat host at halos hindi kailanman ang nais ng isang production job. Kung iginagalang ang isang CIDR entry ay depende sa mga bersyon ng Requests at urllib3 sa image, kaya subukan ang eksaktong entry sa halip na ipagpalagay na gumagana ito. Suriin ang resulta ng should_bypass_proxies para sa tunay na URL, hindi para sa hostname na tina-type mo mula sa memorya.
Panatilihing hiwalay ang dalawang layer sa isip mo. Ang paglampas sa HTTP proxy ay hindi lumalampas sa VPN, dahil ang desisyon sa proxy ay nangyayari sa library at ang desisyon sa tunnel sa routing table ng kernel.
I-disable ang trust_env lamang bilang sinadyang patakaran ng sesyon
Kung dapat balewalain ng buong trabaho ang configuration ng kapaligiran, buuin ang sesyon nang tahasan at itala ang desisyon sa code. Iyon ay patakaran, hindi shortcut, at nabibilang ito sa diff na makikita ng reviewer. Pinapanatili ng halimbawa sa ibaba ang timeout, tahasang CA path at pagsusuri ng status.
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()
Ang pag-off ng trust_env ay nagbabago ng tatlong kilos nang sabay, at isa lang sa kanila ang tungkol sa proxy. Humihinto ang Requests sa pagbasa ng .netrc credentials, at ang mga variable na REQUESTS_CA_BUNDLE at CURL_CA_BUNDLE ay humihinto sa pag-apekto sa verify, na bumabalik naman sa bundled certificate store. Kung tinatapos ng iyong organisasyon ang TLS gamit ang sariling CA, ang fallback na iyon ay naglalabas ng verification error na mukhang walang kaugnayan sa pagbabagong ginawa mo lang. Ang tahasang pagpasa ng verify ang nagpapanatiling hiwalay sa dalawang epekto.
Ang hindi mo dapat gawin ay itakda ang verify=False para patahimikin ang resultang error. Ipinagpapalit niyon ang maling proxy configuration sa isang hindi na-verify na koneksyon, at itinatago ang problema sa certificate na dapat ilantad ng pagbubukod.
I-verify ang layer na nabibigo at panatilihin ang rollback
Tatlong pagkabigo ang magkamukha sa log at walang pagkakatulad: ang proxy na hindi umabot sa destinasyon ay nagbabalik ng ProxyError o 502, ang problema sa tiwala ay nagbabalik ng SSLError, at ang pagtanggi ng application ay nagbabalik ng 401 o 403. Kopyahin muli ang kahilingan sa labas ng Requests para makita kung alin ang mayroon ka. Inaalis ng mga utos sa ibaba ang proxy, sinusubukan ang certificate chain at pagkatapos ay inuulit ang tawag sa pamamagitan ng library.
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)"
Kung nagtagumpay ang curl call at nabigo ang Python call, ang kapaligiran pa rin ang pagkakaiba. Kung parehong nabigo sa TLS stage, hindi kailanman naging problema ang proxy at ang certificate chain ang problema. Kung parehong nagbabalik ng 401, umabot ang kahilingan sa application at ang natitirang trabaho ay authentication. Ang itala kung alin sa tatlo ang naobserbahan mo ay nakakatipid ng isang oras sa susunod na tao.
Ang rollback ay isang linya sa magkabilang direksyon: alisin ang pagbubukod, o ibalik ang trust_env. I-save ang dating halaga ng NO_PROXY bago magdagdag, at mas gusto ang wrapper script o unit-level na Environment= entry kaysa sa export na nabubuhay lamang sa history ng iyong terminal. Parehong nakikita ang dalawang pagbabago sa kapaligiran ng proseso, kaya ang restart ay karaniwang nagbabalik sa iyo sa lumang kilos.
Tapusin sa pamamagitan ng pagkumpirma ng apat na bagay: walang proxy na ipinapakita ang pinagsamang settings para sa pribadong URL, nagva-validate ang certificate laban sa nilalayong CA, nagbabalik ang kahilingan ng status na inaasahan mo, at na-commit ang pagbabago sa lugar na maaaring kopyahin. Ang berdeng script na may hindi maipaliwanag na kapaligiran ay isang pagwawastong muling masisira sa susunod na makina. Ang mga utos sa runbook na ito ang dapat i-paste sa ticket.