ความล้มเหลวสองแบบที่ต่างกันพิมพ์ traceback ของ pip แบบเดียวกัน และการซ่อมที่เหมาะกับแบบหนึ่งกลับทำให้อีกแบบแย่ลง ไคลเอนต์ที่เก่าเกินกว่าจะระบุชื่อโฮสต์ที่ผ่านอุโมงค์ต้องการการอัปเกรด พร็อกซี่ที่ลงนามซ้ำบนทราฟฟิกต้องการใบรับรองรากที่เชื่อถือได้ ไม่ใช่การดาวน์เกรด ระบุว่าคุณมีแบบไหนก่อนแก้ไขตัวแปรพร็อกซี่ เพราะเส้นทางทั้งสองมุ่งไปคนละทิศ

อ่านเฟรมสุดท้ายก่อนแตะการตั้งค่า

จุดที่ traceback สิ้นสุดบอกว่าชั้นไหนยอมแพ้ ถ้าเฟรมปิดท้ายอยู่ในโค้ด TLS ของ urllib3 ที่มาพร้อม pip และข้อความบ่นเรื่องชื่อโฮสต์ แสดงว่าไลบรารีไคลเอนต์ทำงานขั้นตอนตรวจสอบให้เสร็จไม่ได้ และนี่เป็นปัญหาเวอร์ชันบ่อยกว่าปัญหาใบรับรองมาก ถ้าข้อความรายงานการเชื่อมต่อที่ถูกปฏิเสธ ชื่อพร็อกซี่ที่แก้ไม่ตก หรือ ข้อผิดพลาด HTTP 407 แทน แปลว่าจุดปลายของอุโมงค์เป็นต้นเหตุ และไม่มีการอัปเกรดใดจะเปลี่ยนมัน

บันทึกเวอร์ชัน pip และตัวแปรพร็อกซี่ในเชลล์เดียวกับที่ล้มเหลว เชลล์ที่เปิดก่อนอุโมงค์ขึ้นมามีค่าต่างจากเชลล์ที่เปิดหลังจากนั้น และความต่างระหว่างสองอันมักเป็นคำวินิจฉัยทั้งหมด

python3 -m pip --version
env | grep -i -E 'proxy|no_proxy'

เมื่อไคลเอนต์เก่ากว่าอุโมงค์

pip รุ่นเก่าพามาสแต็ก HTTPS ที่สูญเสียชื่อโฮสต์ปลายทางเมื่อซ็อกเก็ตถูกห่อด้วยอุโมงค์ ข้อความ check_hostname คือสิ่งที่สแต็กนั้นปล่อยออกมาเมื่อถึงการตรวจสอบโดยไม่มีชื่อให้เทียบ การอัปเกรดขจัดข้อบกพร่องเพราะไคลเอนต์ใหม่รักษาชื่อไว้ตลอดการจับมือ และการเปลี่ยนแปลงนี้ถูกพอที่จะลองก่อนทุกครั้งที่เฟรมปิดท้ายชี้ไปที่โค้ด TLS ที่มาพร้อมกัน

ถ้าเข้าถึงดัชนีจากเครื่องที่ล้มเหลวไม่ได้ ให้ดาวน์โหลด wheel ปัจจุบันบนโฮสต์ที่ทำได้แล้วติดตั้งจากไฟล์ ใช้ชื่อไฟล์ที่คุณดาวน์โหลดมาจริง ไม่ใช่เวอร์ชันที่คัดลอกจากโพสต์บล็อก

python3 -m pip install --upgrade pip
python3 -m pip install ./pip-24.2-py3-none-any.whl

เมื่อพร็อกซี่ลงนามซ้ำบนทราฟฟิก

พร็อกซี่ที่สิ้นสุด TLS และออกใบรับรองใหม่ภายใต้รากขององค์กรสร้างข้อผิดพลาดอีกแบบ: certificate verify failed ไม่ใช่การบ่นเรื่องชื่อโฮสต์ ความต่างนั้นคือเบาะแส เพราะไคลเอนต์ไปถึงเซิร์ฟเวอร์แล้วปฏิเสธตัวตนที่ถูกแสดงให้เห็น การซ่อมคือเชื่อถือรากนั้นอย่างชัดเจน ไม่ว่าจะสำหรับคำสั่งเดียวหรือผ่านตัวแปร PIP_CERT เพื่อให้ไคลเอนต์สร้างห่วงโซ่ไปยังสิ่งที่พร็อกซี่นำเสนอได้ การเพิ่มรากลงในที่เก็ตความเชื่อถือของระบบก็ใช้ได้ แต่จะเปลี่ยนความเชื่อถือของทุกโปรแกรมบนเครื่อง และนั่นเป็นการตัดสินใจที่ใหญ่กว่าการซ่อมการติดตั้งแพ็กเกจครั้งเดียว

เก็บ --trusted-host ไว้เป็นเครื่องมือวินิจฉัย ไม่ใช่สภาวะถาวร มันปิดการตรวจสอบที่คุณพยายามรักษาไว้ ใบรับรองที่ผิดจริงจึงดูปกติหลังจากนั้น ถ้าคุณใช้มันเพื่อติดตั้งแพ็กเกจหนึ่ง ให้เอาออกและซ่อมห่วงโซ่ก่อนรุ่นถัดไป

โค้ด Python ของคุณเองเพิกเฉยต่อการกำหนดค่าของ pip โดยสิ้นเชิง การเรียก requests ต้องส่งพร็อกซี่และชุดใบรับรองไปยังที่ที่เซสชันนั้นมองเห็น จึงเป็นเหตุให้บล็อกด้านล่างตั้งทั้งสองอย่างบนออบเจ็กต์เซสชัน

pip install --cert /usr/local/share/ca-certificates/corp-root.crt requests
export PIP_CERT=/usr/local/share/ca-certificates/corp-root.crt
s = requests.Session()
s.proxies = {"https": "http://10.20.30.40:8080"}
s.verify = "/usr/local/share/ca-certificates/corp-root.crt"
s.get("https://pypi.org/simple/", timeout=15)

เมื่อจุดปลายหรือพอร์ตผิด

ไคลเอนต์อุโมงค์มักเขียนพร็อกซี่ของระบบใหม่ขณะเชื่อมต่อ ซึ่งอาจทำให้ pip ชี้ไปที่โฮสต์ที่ไม่ตอบบนพอร์ตนั้นเลย ทดสอบจุดปลายด้วยไคลเอนต์ที่ไม่ใช่ pip ก่อนเปลี่ยนการตั้งค่า pip ใด ๆ ถ้า curl ล้มเหลวด้วยอาร์กิวเมนต์พร็อกซี่เดียวกัน แสดงว่าข้อบกพร่องอยู่เหนือ pip และการกำหนดค่าใน pip จะช่วยไม่ได้

แฟล็กคำสั่งและตัวแปรสภาพแวดล้อมพูดสิ่งเดียวกันกับขอบเขตที่ต่างกัน แฟล็กใช้กับการเรียกหนึ่งครั้ง ตัวแปรใช้กับทุกโปรเซสที่เริ่มหลังจากนั้น เพิ่ม NO_PROXY สำหรับดัชนีภายใน เพื่อให้ทราฟฟิกแพ็กเกจส่วนตัวข้ามการอ้อมผ่านอุโมงค์

curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/
pip install --proxy http://proxy.corp.internal:8080 requests

ทำให้การตั้งค่าคงอยู่และพิสูจน์ว่าเส้นทางใช้งานได้

เก็บพร็อกซี่ในการกำหนดค่าของ pip เองเมื่อมันต้องอยู่ต่อจากเชลล์ปัจจุบัน แล้วอ่านกลับว่าจริง ๆ pip จะใช้อะไร เอาต์พุต debug ระบุไฟล์และตัวแปรเบื้องหลังแต่ละค่า ซึ่งยุติข้อโต้แย้งเรื่องลำดับความสำคัญได้เร็วกว่าการอ่านเอกสาร

การตรวจสอบใช้ไคลเอนต์สองตัวโดยเจตนา คำขอจากไลบรารีมาตรฐานพิสูจน์เส้นทางและห่วงโซ่ความเชื่อถือ ส่วนการดาวน์โหลดพิสูจน์ว่าการกำหนดค่าของ pip เองสอดคล้องกับทั้งสอง เมื่อตัวแรกสำเร็จและตัวที่สองล้มเหลว ความต่างอยู่ภายใน pip ไม่ใช่ในเครือข่าย

pip config set global.proxy http://proxy.corp.internal:8080
pip config debug
python3 -c "import urllib.request as r; print(r.urlopen('https://pypi.org/simple/').status)"
pip download --no-deps -d /tmp/wheelcheck requests
What you seeFirst commandRepair
hostname message inside vendored TLS framespython3 -m pip --versionupgrade the client
certificate verify failed after the tunnelcurl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/trust the corporate root
connection refused or HTTP 407env | grep -i -E 'proxy|no_proxy'correct host, port or credentials

บทความที่เกี่ยวข้อง