407 代理身份验证要求:每个原因及其解决方法

HTTP 407 只有一个含义:前面的代理拒绝了您的凭据。这个单一事实消除了大多数错误的方向——这里是剩下的地图。

HTTP 407 代理身份验证要求只有一个含义,比大多数人想象的要狭窄:一个位于您和互联网之间的代理拒绝了请求,因为它缺乏有效的凭据针对代理本身。目标网站从未被联系。它从未看到您的请求,从未做出决定,也不可能是原因。因此,修复 407 总是意味着修复您的代理配置——可以出错的事情列表很短且完全可枚举。本指南涵盖了整个列表,包括最容易让人困惑的工具特定修复。

首先阅读 Proxy-Authenticate 头

根据 HTTP 规范 (RFC 9110),407 必须伴随一个描述如何进行身份验证的Proxy-Authenticate头——通常是类似Proxy-Authenticate: Basic realm="Access to internal site"的内容。然后,您的客户端应重复请求并带有Proxy-Authorization头。这个配对值得记住,因为它是 407 与其邻居的区别:401 来自源服务器,并将WWW-AuthenticateAuthorization配对,而407来自中介,并使用Proxy-前缀版本。如果您盯着WWW-Authenticate头,您正在调试错误的跳跃。

# See exactly which hop is refusing you, and what scheme it wants
curl -v -x http://USER:PASS@gate.quantumproxies.io:8000 https://httpbin.org/ip

# Response you are looking for on failure:
#   HTTP/1.1 407 Proxy Authentication Required
#   Proxy-Authenticate: Basic realm="..."
#
# Response you want on success: your exit IP, not your own
#   {"origin": "203.0.113.45"}

如果curl -x带凭据返回您的出口 IP,代理和凭据都没问题——您在应用程序中仍然看到的任何 407 都是该应用程序自己的配置,而不是代理的。这个简单的测试在大约十秒钟内将问题一分为二。

原因 1:凭据缺失、错误或位置错误

最常见的原因也是最无聊的。凭据属于代理 URL,在主机之前,以user:pass@host:port形式——客户端库从中构建Proxy-Authorization头。从仪表板复制一个端点而没有凭据,或者粘贴您的帐户密码而不是代理密码(它们通常不同),会在每个请求上立即产生永久的 407。

import requests

proxy = "http://USER:PASS@gate.quantumproxies.io:8000"
proxies = {"http": proxy, "https": proxy}

r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=15)
print(r.status_code, r.json())   # 200 and the exit IP = auth is correct

也要检查端口。提供商为旋转和粘性端点以及 HTTP 与 SOCKS5 暴露不同的端口;即使凭据有效,命中错误的端口仍可能返回 407,因为该监听器期望不同的身份格式。如果您不确定您使用的是哪个协议,我们关于SOCKS5 与 HTTP 代理的解释说明了区别。

原因 2:从未进行百分比编码的特殊字符

这一个让人们浪费了整个下午。代理 URL 是一个 URL,因此用户名或密码中的任何保留字符都必须进行百分比编码,否则解析器会在错误的位置拆分字符串。包含@的密码会提前结束用户信息部分,您的客户端尝试连接到不存在的主机;:在错误的位置将用户名与密码分开。

from urllib.parse import quote

user = quote("team@example.com", safe="")   # team%40example.com
pwd  = quote("p@ss:w#rd", safe="")          # p%40ss%3Aw%23rd

proxy = f"http://{user}:{pwd}@gate.quantumproxies.io:8000"
将 407 代理身份验证要求症状映射到其真实原因的清单,包括隧道故障、白名单更改和每个工具的代理设置
相同的状态代码,六种不同的故障。在更改任何内容之前,请先匹配左侧的症状。

原因 3:白名单身份验证和移动的 IP

大多数提供商支持两种身份验证模式:URL 中的凭据或 IP 白名单,您在仪表板中授权服务器的公共地址,并且不发送任何凭据。QuantumProxies 支持两者。故障模式是特定且非常可识别的:一切工作了几周,然后每个请求开始返回 407 而没有代码更改。这是您的公共 IP 更改——办公室的 DHCP 租约续约,云重新部署后的新 NAT 网关,移动网络共享,或每个作业获取新地址的 CI 运行器。

在调试其他任何内容之前确认这一点:使用curl -sS https://api.ipify.org获取您当前的公共地址,将其与白名单进行比较,如果不同则重新添加。如果您的出口 IP 不稳定——CI 运行器和自动缩放组很少稳定——将该环境切换到user:pass身份验证,它随配置而不是网络一起传输。这个陷阱的另一半是混合模式:一些网关在仅白名单端点上拒绝凭据,因此发送两者可能会失败,而发送都不发送则成功。

原因 4:HTTPS 通过 CONNECT 隧道

仅在https:// URL 上出现的 407,通常作为 Python 错误OSError: Tunnel connection failed: 407 Proxy Authentication Required,具有结构性原因。普通 HTTP 请求由代理转发,但 HTTPS 请求首先通过CONNECT请求打开一个隧道——而该 CONNECT 携带自己的Proxy-Authorization头。如果您的配置仅设置了 HTTP 代理,或在一个方案上设置了凭据而不是另一个,隧道将匿名尝试并在 TLS 开始之前被拒绝。

规则很简单:始终使用相同的凭据配置两个方案。在 Python 中,这意味着proxies字典中的两个键;在 shell 中,这意味着HTTP_PROXYHTTPS_PROXY;在 npm 中,这意味着proxyhttps-proxy。请注意,HTTPS_PROXY几乎总是采用http://方案——该方案描述了您如何与代理通信,而不是您通过它获取的内容。

// Node 18+ with undici: one dispatcher covers http and https targets
import { ProxyAgent, fetch } from "undici";

const dispatcher = new ProxyAgent(
  "http://USER:PASS@gate.quantumproxies.io:8000"
);

const res = await fetch("https://httpbin.org/ip", { dispatcher });
console.log(res.status, await res.json());

原因 5:工具有自己的代理配置

环境变量并非通用。许多工具读取自己的配置文件并完全忽略 shell,这产生了令人恼火的状态,即curl工作而您的构建不工作。一个长期存在的 GitHub Desktop 问题是教科书式的例子:一个开发人员在公司代理后面设置了.gitconfig和环境中的代理,但登录仍然失败,出现 407 和net::ERR_TUNNEL_CONNECTION_FAILED——因为 git 配置仅对 git 进行身份验证,而进行 OAuth 流程的嵌入式浏览器没有自己的代理凭据。每个子系统都需要单独告知。

# shell-wide (respected by curl, wget, pip, most SDKs)
export HTTP_PROXY="http://USER:PASS@gate.quantumproxies.io:8000"
export HTTPS_PROXY="$HTTP_PROXY"
export NO_PROXY="localhost,127.0.0.1,.internal"

# npm - both keys, or https installs will 407
npm config set proxy       "$HTTP_PROXY"
npm config set https-proxy  "$HTTPS_PROXY"

# git
git config --global http.proxy  "$HTTP_PROXY"
git config --global https.proxy "$HTTPS_PROXY"

# apt - /etc/apt/apt.conf.d/95proxies
# Acquire::http::Proxy  "http://USER:PASS@gate.quantumproxies.io:8000";
# Acquire::https::Proxy "http://USER:PASS@gate.quantumproxies.io:8000";

在编辑所有这些文件时的一项安全提示:全局 git 或 npm 配置中的凭据最终以明文形式出现,嵌入密码的代理 URL 会泄漏到 shell 历史记录、CI 日志和错误跟踪中。在具有稳定地址的机器上,IP 白名单完全避免了秘密。

用户:pass 代理身份验证与 IP 白名单身份验证的比较,显示便携性和秘密处理的权衡
凭据随您的配置一起传输;白名单随您的网络一起传输。根据环境选择,永远不要同时选择两者。

407 从来不是目标站点的错

值得重申,因为它可以让您免于追逐幽灵。如果您收到 407,无论旋转用户代理、添加头还是更改出口国家都无济于事——请求尚未离开您的代理。从目标站点来的阻止看起来不同:403 Forbidden表示站点拒绝了您,而429 Too Many Requests表示您速度太快。在编写任何代码之前,诊断您实际拥有的三者中的哪一个。如果 Python 抛出ProxyErrorSSLError而不是干净的 407,我们的调试 Requests 中的 ProxyError指南涵盖了传输级别的故障。

常见问题解答

如何解决 407 代理身份验证要求?

将有效的凭据放在代理 URL 中作为http://user:pass@host:port,对任何保留字符进行百分比编码,并配置 HTTP 和 HTTPS 代理设置。如果您的提供商使用 IP 白名单,请授权您当前的公共 IP 并不发送凭据。在触及您的应用程序代码之前,使用curl -x对 IP 回显服务进行验证。

407 代理身份验证要求是什么意思?

这意味着中介代理因缺乏有效的代理凭据而拒绝了请求。响应包括一个Proxy-Authenticate头,命名方案,客户端应重试并带有Proxy-Authorization。它与 401 不同,401 来自目标服务器,而不是中间的代理。

如何修复 npm 错误 407?

设置两个键:npm config set proxynpm config set https-proxy,每个都有完整的http://user:pass@host:port URL。注册表流量是 HTTPS,因此仅 HTTP 设置在 CONNECT 隧道处失败。对密码中的特殊字符进行百分比编码,并检查是否有项目级.npmrc覆盖您的全局配置。

为什么 Python 会引发 Tunnel connection failed: 407?

因为 HTTPS 请求打开了一个没有携带代理凭据的 CONNECT 隧道。将proxies字典中的httphttps键都设置为相同的认证 URL。还要检查环境中的HTTP_PROXYHTTPS_PROXY是否覆盖了您的字典——设置session.trust_env = False以排除这一点。

如何在 Postman 中设置代理身份验证?

打开设置,转到代理选项卡,启用自定义代理配置,输入主机和端口,然后勾选代理身份验证框并添加用户名和密码。依赖于系统代理切换是常见错误——它通过代理路由流量但从不提供凭据,因此每个请求都返回 407。

五个原因几乎涵盖了所有 407:缺少凭据、未编码的特殊字符、已更改的白名单 IP、未经身份验证的 CONNECT 隧道以及具有自身配置的工具。按此顺序处理它们,状态代码就会消失——然后您可以开始担心目标站点对您的看法。

获取具有用户:pass 或 IP 白名单身份验证的住宅代理