请求库通过代理进行HTTPS GET导致错误

4

尝试通过代理发送简单的GET请求。我有“Proxy-Authorization”和“Authorization”标头,不认为我需要“Authorization”标头,但无论如何都添加了它。

import requests
URL = 'https://www.google.com'
sess = requests.Session()
user = 'someuser'
password = 'somepass'
token = base64.encodestring('%s:%s'%(user,password)).strip()
sess.headers.update({'Proxy-Authorization':'Basic %s'%token})
sess.headers['Authorization'] = 'Basic %s'%token
resp = sess.get(URL)

I get the following error:

requests.packages.urllib3.exceptions.ProxyError: Cannot connect to proxy. Socket error: Tunnel connection failed: 407 Proxy Authentication Required.

然而,当我将URL更改为简单的http://www.google.com时,它可以正常工作。
代理是否对HTTPS使用基本身份验证、摘要身份验证或其他类型的身份验证?这是代理服务器特定的吗?我如何发现这些信息?我需要使用requests库来实现这一点。
更新:似乎在HTTP请求中,我们必须传递一个Proxy-Authorization头,但在HTTPS请求中,我们需要使用用户名和密码格式化代理URL。
#HTTP
import requests, base64
URL = 'http://www.google.com'
user = <username>
password = <password>
proxy = {'http': 'http://<IP>:<PORT>}
token = base64.encodestring('%s:%s' %(user, password)).strip()
myheader = {'Proxy-Authorization': 'Basic %s' %token}
r = requests.get(URL, proxies = proxies, headers = myheader)
print r.status_code # 200


#HTTPS
import requests
URL = 'https://www.google.com'
user = <username>
password = <password>
proxy = {'http': 'http://<user>:<password>@<IP>:<PORT>}
r = requests.get(URL, proxies = proxy)
print r.status_code  # 200

发送HTTP请求时,如果我省略了头部并传递一个带有用户名/密码格式的代理,我会收到407响应。

发送HTTPS请求时,如果我传递了头部但未格式化代理,则会出现先前提到的ProxyError错误。

我正在使用requests 2.0.0和Squid代理缓存Web服务器。为什么头选项在HTTPS上不起作用?为什么格式化的代理在HTTP上不起作用?


认证是代理服务器特定的。您可以通过与负责代理服务器的人交谈或可能阅读文档来发现必要的配置。您可以尝试配置浏览器使用代理服务器,并查看是否可以将其作为测试不同配置的方法。 - larsks
1个回答

7
答案是HTTP出现了错误。在这种情况下,期望的行为与HTTPS相同:也就是,在代理URL中提供您的身份验证凭据。
HTTPS中头选项不起作用的原因是,通过代理的HTTPS与通过代理的HTTP完全不同。当您通过代理路由HTTP请求时,您基本上只需向代理发送一个标准的HTTP请求,并使用指示完全不同主机的路径,如下所示:
GET http://www.google.com/ HTTP/1.1
Host: www.google.com

代理服务器基本上只是将这个请求转发出去。
对于 HTTPS,这种方法不可能奏效,因为需要与远程服务器协商 SSL 连接。与 HTTP 情况不同,你需要使用 CONNECT 动词。代理服务器代表客户端连接到远程端,并从此之后仅代理 TCP 数据。(更多信息请参考这里。)
当你在 HTTPS 请求中添加一个 Proxy-Authorization 头时,我们不会将其放在 CONNECT 消息中,而是将其放在隧道化的 HTTPS 消息中。这意味着代理服务器永远不会看到它,因此会拒绝你的连接。我们针对代理 URL 中的身份验证信息进行特殊处理,以确保正确地将头部附加到 CONNECT 消息中。
Requests 和 urllib3 目前正在讨论此错误修复的正确位置。GitHub 的问题当前位于这里。我希望修复将包含在下一个 Requests 发布中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接