概览
操作流程
确认实际线路
记录发生故障的运行环境使用的代理主机、端口和协议。
检查 CONNECT 并重试
读取 CONNECT 响应,修复对应问题,再访问原始目标。
ERR_TUNNEL_CONNECTION_FAILED 表示 Chromium 无法通过配置的代理建立隧道。先确认 Chrome 实际使用哪个代理,再检查代理对 HTTPS CONNECT 请求的响应。密码问题、不支持的目标端口与上游连接故障,需要采取不同的修复措施。
这个错误也可能出现在 Edge,或由 Playwright、Puppeteer 启动的 Chromium 浏览器中。请从实际发起请求的设备或容器里排查。
下一步
失败的是代理连接,还是 HTTPS 隧道?

通过 HTTP 代理发起 HTTPS 请求时,客户端先连接代理,再请求代理连接目标主机和端口。隧道建立后,客户端才能通过这条线路与目标协商 TLS。
观察到的结果 | 优先排查 |
|---|---|
ERR_PROXY_CONNECTION_FAILED | 客户端能否访问配置的代理端点 |
ERR_TUNNEL_CONNECTION_FAILED | CONNECT 交换、代理策略、鉴权和后续连接 |
代理返回 HTTP 407 | 要求的代理鉴权方式与所提供的凭据 |
隧道建立后出现证书校验错误 | 相关 TLS 连接的证书链和主机名 |
这些结果对应不同的失败阶段。Chromium 在网络错误定义中,将隧道错误与代理连接错误分开定义。仅凭这一错误,无法确定服务商的哪个组件发生故障,也不能证明目标服务本身正常。
1. 确认当前实际生效的代理
检查 Chrome 的系统代理设置入口、当前浏览器配置中启用的代理扩展,以及会写入系统代理的 VPN 或本地客户端。受管理设备还可能通过策略或 PAC 文件选择线路。修改前先记录实际使用的主机、端口和协议。
如果端点是 127.0.0.1,代理必须在同一个网络环境里运行。在容器中,这个地址指向容器自身。如果旧设置已不再需要,应通过拥有该设置的应用将其移除,再重新测试。组织要求保留的线路应由管理员管理。
使用 MIYAIP 时,应填写分配的连接端点,而不是界面显示的出口 IP。原生与中转连接可能需要不同的网络路径。静态代理接入教程介绍了连接字段和路由条件。
2. 通过同一个 HTTP 代理测试 HTTPS 请求
替换下面三个占位字段后,在 macOS 或 Linux 运行命令。只提供用户名时,curl 会提示输入代理密码。示例目标是 example.com;随后可以改用失败的 HTTPS 目标进行比较。代理地址应采用服务商实际提供的 HTTP 或 HTTPS 协议。
curl --proxy 'http://PROXY_HOST:PROXY_PORT' \
--proxy-user 'PROXY_USERNAME' --noproxy '' \
--connect-timeout 10 --max-time 30 \
--silent --show-error --output /dev/null \
--write-out 'connect_status=%{http_connect} target_status=%{http_code}\n' \
'https://example.com/'Windows 请使用 curl.exe,将命令写在一行,并把 /dev/null 替换为 NUL。检查实际运行环境中的 NO_PROXY 排除设置;较旧的 PowerShell 版本不一定按预期传递空的原生命令参数。
connect_status 表示 HTTP 代理的 CONNECT 响应。000 表示未记录到此类响应码,本身不说明原因。CONNECT 成功与目标响应成功是两个独立的观察结果。对于 SOCKS5 代理,请使用对应协议的连接示例,不要期待获得 HTTP CONNECT 状态。
3. 根据响应决定下一步检查
结果 | 下一步操作 |
|---|---|
CONNECT 407 | 确认代理凭据、账户状态和鉴权模式。账户登录密码或 API token 并不自动等同于代理密码 |
CONNECT 403 | 检查代理对目标地址和端口的策略。如果这条线路本应允许访问,向支持人员提供目标主机、端口和时间戳 |
CONNECT 429 | 降低请求并发,并遵循服务商的重试建议。反复重发相同请求可能延长问题持续时间 |
CONNECT 502/503/504 | 与另一个允许访问的目标比较,并检查服务商状态。记录问题只影响一个目标,还是影响所有目标 |
CONNECT 成功,但下一步失败 | 检查实际报告的 TLS 或目标错误;此时隧道本身已经打开 |
curl 成功,但 Chrome 失败 | 将浏览器配置、扩展、PAC 规则和鉴权方式与成功测试所用配置进行比较 |
在线代理检查器可以提供另一个观察位置。它的服务器与笔记本、办公网络或容器可能使用不同线路,因此远程检查成功不能替代同设备测试。
验证原始目标
回到原先的 Chrome 配置,重新打开失败的 URL。然后使用 IP 与浏览器环境检查,查看实际观察到的出口。请同时保留目标访问结果和出口结果;只有其中一项,还不足以验证整条线路。
常见问题
为什么 HTTP 页面可以访问,HTTPS 页面却失败?
HTTP 代理可能接受普通 HTTP 请求,却拒绝 CONNECT 请求或某些目标端口。修改 DNS 或清理浏览器存储前,应先比较 CONNECT 响应。
应该先清除 Cookie 吗?
Cookie 无法修复被拒绝的 CONNECT 请求。代理和 HTTPS 路径正常后,再检查网站会话问题。
更换代理 IP 能解决这个错误吗?
取决于原因。错误的密码或被禁止的目标端口,可能在任何出口上都失败。应先纠正已经识别的原因,再考虑更换产品或地区。
确认端点和浏览器线路
测试分配的连接字段,再从实际执行任务的浏览器中检查出口和目标。
下一步
运行本地演示
下载 network_demo.py,或将以下完整代码保存为同名文件。使用 Python 3 运行 python network_demo.py。服务仅监听 127.0.0.1:8766,使用完按 Ctrl+C 退出。
"""Local HTTP demonstration. No external requests, credentials or MIYAIP service calls."""
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlsplit
import json
import time
class DemoHandler(BaseHTTPRequestHandler):
def log_message(self, *_):
pass
def reply(self, code, body=b"", headers=None):
self.send_response(code)
for key, value in (headers or {}).items():
self.send_header(key, value)
self.send_header("Content-Length", str(len(body)))
try:
self.end_headers()
self.wfile.write(body)
except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError):
pass
def do_CONNECT(self):
self.reply(407, headers={"Proxy-Authenticate": 'Basic realm="local-demo"'})
def do_GET(self):
path = urlsplit(self.path).path
if path == "/redirect":
return self.reply(302, headers={"Location": "/headers"})
if path == "/loop":
return self.reply(302, headers={"Location": "/loop"})
if path == "/slow":
time.sleep(2)
if path in {"/headers", "/slow"}:
payload = {"method": self.command, "headers": dict(self.headers)}
return self.reply(200, json.dumps(payload, indent=2).encode(),
{"Content-Type": "application/json"})
self.reply(404, b"Use /headers, /redirect, /loop or /slow")
def do_POST(self):
body = self.rfile.read(int(self.headers.get("Content-Length", "0")))
if urlsplit(self.path).path == "/redirect307":
return self.reply(307, headers={"Location": "/headers"})
if urlsplit(self.path).path == "/redirect302":
return self.reply(302, headers={"Location": "/headers"})
payload = {"method": self.command, "headers": dict(self.headers),
"body": body.decode("utf-8", errors="replace")}
self.reply(200, json.dumps(payload, indent=2).encode(),
{"Content-Type": "application/json"})
if __name__ == "__main__":
print("Local demonstration: http://127.0.0.1:8766 (Ctrl+C to stop)", flush=True)
ThreadingHTTPServer(("127.0.0.1", 8766), DemoHandler).serve_forever()