Requests ProxyError კერძო API-ზე? ჯერ გარემო შეამოწმეთ
Requests აერთიანებს პროქსის, ავთენტიფიკაციისა და CA-ის პარამეტრებს გარემოდან. წაიკითხეთ, რას ხედავს პროცესი, გამორიცხეთ კერძო ჰოსტი და დატოვეთ TLS-ის შემოწმება ჩართული.
VPN ჩართულია, შიდა დაფა ბრაუზერში იხსნება, და Python-ის სკრიპტი მაინც პროქსის შეცდომას იძლევა. ამ სურათში გვირაბს არაფერი სჭირს: ინტერპრეტატორი პროქსის მისამართს საკუთარი გარემოდან კითხულობს და მოთხოვნას იქ აგზავნის. ეს სახელმძღვანელო კითხულობს იმ გარემოს, რომელსაც პროცესი რეალურად ხედავს, ზომავს ყველაზე ვიწრო გამორიცხვას და მხოლოდ ამის შემდეგ განიხილავს სესიის მკაფიო პოლიტიკას. ყოველი ნაბიჯი მთავრდება ბრძანებით, რომლის გამოტანა წყვეტს, გააგრძელებთ თუ არა.
წაიკითხეთ გარემო, რომელსაც პროცესი რეალურად ხედავს
სამუშაო მაგიდის პროქსის პარამეტრები, shell-ის ექსპორტები და systemd-ის ერთეულის Environment= სტრიქონები სამი განსხვავებული წყაროა, და Requests კითხულობს მხოლოდ ბოლოს, რომელსაც მემკვიდრეობით იღებს. გაუშვით ქვემოთ მოცემული დიაგნოსტიკა იმავე shell-ში, კონტეინერში ან ერთეულში, რომელიც წარუმატებელ სკრიპტს უშვებს, და არა თქვენს ინტერაქტიულ ტერმინალში. თქვენს შესვლის shell-ში ექსპორტირებული ცვლადი კონტეინერის პროცესისთვის უხილავია, და ეს სხვაობა ხსნის უამრავ ცნობას იმ პროქსიზე, რომელიც არსად იჩენს თავს. ორი ბრძანება ერთსა და იმავე მონაცემს სხვადასხვა დეტალურობით ბეჭდავს.
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-ზე გავლენას, რომელიც შემდეგ ჩაშენებულ სერთიფიკატების საცავზე გადადის. თუ თქვენი ორგანიზაცია TLS-ს საკუთარი CA-ით ამთავრებს, ეს უკან დაბრუნება იწვევს შემოწმების შეცდომას, რომელიც ახლახან გაკეთებულ ცვლილებასთან უკავშიროდ გამოიყურება. 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-ის წინააღმდეგ, მოთხოვნა აბრუნებს თქვენ მიერ მოსალოდნელ სტატუსს, და ცვლილება ჩაწერილია აღწარმოებად ადგილას. გაუხსნელი გარემოთი მწვანე სკრიპტი ის შესწორებაა, რომელიც შემდეგ მანქანაზე ისევ გატყდება. ამ სახელმძღვანელოს ბრძანებებია ის, რაც ბილეთში უნდა ჩასვათ.