निजी API पर Requests ProxyError? पहले वातावरण जाँचें
Requests प्रॉक्सी, auth और CA सेटिंग्स को वातावरण से मिलाता है। प्रक्रिया जो देखती है उसे पढ़ें, निजी होस्ट को बाहर रखें और TLS सत्यापन चालू रखें।
VPN चालू है, आंतरिक डैशबोर्ड ब्राउज़र में खुलता है, और Python स्क्रिप्ट फिर भी प्रॉक्सी त्रुटि देती है। उस तस्वीर में सुरंग में कुछ गड़बड़ नहीं है: इंटरप्रेटर अपने ही वातावरण से प्रॉक्सी पता पढ़ता है और अनुरोध वहीं भेजता है। यह मार्गदर्शिका वह वातावरण पढ़ती है जो प्रक्रिया वास्तव में देखती है, सबसे संकीर्ण बहिष्करण लागू करती है और उसके बाद ही स्पष्ट सत्र नीति पर विचार करती है। हर चरण एक ऐसी कमांड पर समाप्त होता है जिसका आउटपुट तय करता है कि आप आगे बढ़ेंगे या नहीं।
वह वातावरण पढ़ें जो प्रक्रिया वास्तव में देखती है
डेस्कटॉप प्रॉक्सी सेटिंग्स, शेल एक्सपोर्ट और systemd यूनिट की Environment= पंक्तियाँ तीन अलग स्रोत हैं, और Requests केवल वही अंतिम स्रोत पढ़ता है जो उसे विरासत में मिलता है। नीचे दिया गया निदान उसी शेल, कंटेनर या यूनिट में चलाएँ जो विफल स्क्रिप्ट चलाता है, अपने इंटरैक्टिव टर्मिनल में नहीं। आपके लॉगिन शेल में एक्सपोर्ट किया गया वेरिएबल कंटेनर प्रक्रिया के लिए अदृश्य है, और यही अंतर कहीं से भी प्रकट होने वाले प्रॉक्सी की कई रिपोर्टों की व्याख्या करता है। दोनों कमांड वही डेटा अलग-अलग विस्तार स्तरों पर छापती हैं।
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()]"
प्रत्येक वेरिएबल की दोनों वर्तनियाँ पढ़ी जाती हैं, और डुप्लिकेट प्रविष्टियाँ उसी क्रम में लागू होती हैं जिसमें प्रक्रिया को वे मिलीं, इसलिए पुराना HTTP_PROXY उस मान को ओवरराइड कर सकता है जिसे आपने अभी एक्सपोर्ट किया है। CA-बंडल वेरिएबल यहाँ भी मायने रखते हैं, क्योंकि वे बदलते हैं कि verify किसमें हल होता है, बिना कोड में कहीं दिखे। यदि आउटपुट खाली है, तो वातावरण आपकी समस्या नहीं है और आप यह खंड पढ़ना बंद कर सकते हैं। यदि यह ऐसा प्रॉक्सी सूचीबद्ध करता है जिसे आप नहीं पहचानते, तो कुछ भी बदलने से पहले उसे सेट करने वाली फ़ाइल या यूनिट खोजें।
Requests से पूछें कि वह किसी विशिष्ट URL के साथ क्या करेगा। यह कॉल बिना कोई पैकेट भेजे उस अनुरोध के लिए मिलाए गए प्रॉक्सी, verify और cert मान दिखाता है।
python3 -c "import requests;s=requests.Session();print(s.merge_environment_settings('https://api.corp.example/status',{},None,None,None))"
निजी होस्ट के लिए खाली न होने वाली proxies प्रविष्टि आपका उत्तर है, और छपा हुआ verify मान बताता है कि अनुरोध किस CA-बंडल पर भरोसा करेगा। यदि दोनों सही लगते हैं, तो विफलता स्टैक में बाद में है और आपको सत्यापन खंड पर जाना चाहिए। कोड से अनुमान न लगाएँ: मिलान प्रति अनुरोध होता है, इसीलिए एक सत्र दो होस्ट के लिए अलग व्यवहार कर सकता है।
कुछ भी अक्षम करने से पहले निजी होस्ट को बाहर रखें
जब अन्य गंतव्यों के लिए प्रॉक्सी वास्तव में आवश्यक हो, तो संकीर्ण समाधान इस होस्ट के लिए बहिष्करण है। मौजूदा सूची में जोड़ें, उसे बदलें नहीं, क्योंकि NO_PROXY को मिटाने से हर वह अन्य आंतरिक गंतव्य टूट जाता है जो उस पर निर्भर था। नीचे दी गई कमांड प्रविष्टि जोड़ती हैं और फिर Requests से पूछती हैं कि बायपास लागू होता है या नहीं।
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))"
मिलान होस्ट प्रत्यय के अनुसार होता है, इसलिए .corp.example पूरे डोमेन को कवर करता है जबकि api.corp.example एक नाम को कवर करता है। अकेला तारांकन हर होस्ट के लिए प्रॉक्सी अक्षम करता है और प्रोडक्शन कार्य लगभग कभी यही नहीं चाहता। CIDR प्रविष्टि मानी जाएगी या नहीं, यह इमेज में Requests और urllib3 के संस्करणों पर निर्भर करता है, इसलिए काम करने का अनुमान लगाने के बजाय ठीक वही प्रविष्टि परखें। should_bypass_proxies का परिणाम असली URL के लिए जाँचें, स्मृति से टाइप किए गए होस्टनाम के लिए नहीं।
दोनों परतों को अपने मन में अलग रखें। HTTP प्रॉक्सी को बायपास करना VPN को बायपास नहीं करता, क्योंकि प्रॉक्सी का निर्णय लाइब्रेरी में और सुरंग का निर्णय कर्नेल की रूटिंग तालिका में होता है।
trust_env को केवल जानबूझकर ली गई सत्र नीति के रूप में ही अक्षम करें
यदि पूरे कार्य को आसपास का कॉन्फ़िगरेशन अनदेखा करना है, तो सत्र को स्पष्ट रूप से बनाएँ और निर्णय कोड में दर्ज करें। यह नीति है, कामचलाऊ उपाय नहीं, और यह ऐसे diff में है जिसे समीक्षक देख सके। नीचे का उदाहरण टाइमआउट, स्पष्ट CA पथ और स्थिति जाँच रखता है।
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()
trust_env बंद करने से एक साथ तीन व्यवहार बदलते हैं, और उनमें से केवल एक प्रॉक्सी के बारे में है। Requests .netrc क्रेडेंशियल पढ़ना बंद कर देता है, और REQUESTS_CA_BUNDLE तथा CURL_CA_BUNDLE वेरिएबल verify को प्रभावित करना बंद कर देते हैं, जो तब साथ आए सर्टिफ़िकेट स्टोर पर लौट जाता है। यदि आपका संगठन अपने CA के साथ TLS समाप्त करता है, तो यह फ़ॉलबैक ऐसी सत्यापन त्रुटि देता है जो अभी किए गए बदलाव से असंबद्ध लगती है। verify को स्पष्ट रूप से पास करना ही दोनों प्रभावों को अलग रखता है।
आपको जो नहीं करना चाहिए वह है परिणामी त्रुटि शांत करने के लिए verify=False सेट करना। इससे प्रॉक्सी की गलत कॉन्फ़िगरेशन के बदले असत्यापित कनेक्शन आता है, और यह उस सर्टिफ़िकेट समस्या को छिपा देता है जिसे बहिष्करण को उजागर करना था।
विफल परत सत्यापित करें और वापस लौटाने की क्षमता रखें
तीन विफलताएँ लॉग में एक जैसी दिखती हैं और उनमें कुछ भी साझा नहीं है: गंतव्य तक न पहुँचने वाला प्रॉक्सी ProxyError फेंकता है या 502 लौटाता है, भरोसे की समस्या SSLError फेंकती है, और एप्लिकेशन का अस्वीकरण 401 या 403 लौटाता है। अनुरोध को Requests के बाहर दोहराएँ ताकि पता चले कि आपके पास कौन-सी है। नीचे दी गई कमांड प्रॉक्सी हटाती हैं, सर्टिफ़िकेट श्रृंखला परखती हैं और फिर लाइब्रेरी से कॉल दोहराती हैं।
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)"
यदि curl कॉल सफल होती है और Python कॉल विफल करती है, तो अंतर अब भी वातावरण है। यदि दोनों TLS चरण पर विफल हों, तो प्रॉक्सी कभी समस्या नहीं थी और सर्टिफ़िकेट श्रृंखला समस्या है। यदि दोनों 401 लौटाएँ, तो अनुरोध एप्लिकेशन तक पहुँच गया और शेष कार्य प्रमाणीकरण है। तीनों में से किसे आपने देखा, यह दर्ज करना अगले व्यक्ति का एक घंटा बचाता है।
वापस लौटाना किसी भी दिशा में एक पंक्ति है: बहिष्करण हटाएँ, या trust_env को वापस पलटें। जोड़ने से पहले पिछला NO_PROXY मान सहेजें, और केवल आपके टर्मिनल इतिहास में जीवित रहने वाले एक्सपोर्ट के बजाय रैपर स्क्रिप्ट या यूनिट-स्तर की Environment= प्रविष्टि को प्राथमिकता दें। दोनों बदलाव प्रक्रिया के वातावरण में दिखते हैं, इसलिए पुनः आरंभ आमतौर पर आपको पुराने व्यवहार पर लौटा देता है।
चार बातें पुष्ट करके समाप्त करें: निजी URL की मिलाई गई सेटिंग्स कोई प्रॉक्सी नहीं दिखातीं, सर्टिफ़िकेट इच्छित CA के विरुद्ध सत्यापित होता है, अनुरोध वह स्थिति लौटाता है जिसकी आप अपेक्षा करते हैं, और बदलाव कहीं पुनरुत्पाद्य जगह पर कमिट किया गया है। अस्पष्ट वातावरण के साथ हरी स्क्रिप्ट ऐसा सुधार है जो अगली मशीन पर फिर टूटता है। इस मार्गदर्शिका की कमांड टिकट में चिपकाने वाली हैं।