尴尬一刻:TLS connect error 突如其来

早上9点,心情正好,我正准备拉取公司的 Git 仓库的远程分支。手指在键盘上飞舞,敲下:

git remote update origin --prune

然而,屏幕上的输出却让我瞬间清醒:
 

fatal: unable to access 'https://code.iflytek.com/EPD_TPD_AIP/1lm/NeuralUI.git/': 
TLS connect error: error:0A080126:SSL routines::unexpected eof while reading

“what?TLS 错误?SSL 读取意外结束?”我盯着这串天书般的报错,大脑飞速运转——昨天还好好的,今天怎么就抽风了?难道是公司网络又在搞升级?还是 Git 服务器傲娇了?

我试着用浏览器打开那个地址,一切正常。ping 也通。也可以正常提交和拉取代码。唯独更新远程分支失败,像是被什么东西掐住了喉咙,死活连不上。

问题重现:一个命令引发的“血案”

为了找到真凶,我回顾了最近的操作。突然想起,昨天为了体验最新的 Claude Code AI 助手,我按照官方文档配置了代理:

$env:HTTPS_PROXY="http://129.211.81.198:xxxxx"
$env:HTTP_PROXY="http://129.211.81.198:xxxxx"

当时想着让 Claude Code 能够顺畅访问外部 API,就在系统设置中添加了这两个环境变量。之后 Claude Code 玩得挺嗨,完全没意识到这个代理设置已经悄悄潜伏在终端会话中,等待着给 Git 致命一击。

果不其然,再次打开终端,这两个变量依然存在。Git 傻乎乎地以为所有 HTTPS 请求都需要经过那个代理服务器,包括访问公司内网的 code.iflytek.com。代理服务器尝试转发请求,但内网地址显然不在它的服务范围内,于是连接被异常中断,Git 收到了一个“unexpected eof”——就像你打电话给快递员,让他帮你取一个放在自家客厅的包裹,快递员一脸懵逼,直接挂了电话。

代理的“功”与“过”

代理,这个网络世界里的“中间人”,平时为我们翻山越岭,访问外网资源立下汗马功劳。它可以加速请求、缓存数据、隐藏真实 IP……但就像快递员一样,它只擅长处理那些需要跨域、跨网络的包裹。对于公司内网这种“家门口”的服务,强行让代理介入,反而会适得其反。

问题就出在这里:当我们设置了 HTTP_PROXY 和 HTTPS_PROXY 环境变量,几乎所有遵循该标准的网络工具(如 curl, wget, git 等)都会默认使用这个代理。如果代理无法访问某些内网地址,就会导致连接失败,甚至抛出 TLS 错误——因为代理服务器在 TLS 握手阶段就中断了连接,Git 收到的自然是一个“不完整”的回应。

求救1:no_proxy 环境变量

解决这个问题的思路很直接:告诉 Git,哪些地址不需要经过代理。这就是 no_proxy(或 NO_PROXY)环境变量的使命。

no_proxy 是一个逗号分隔的列表,用于指定不应使用代理的主机名、IP 地址或域名。我们可以把公司内网的相关域名加进去,让 Git 绕过代理,直接连接。

对于我们这个案例,需要排除的地址包括:

  • localhost 和 127.0.0.1(本地回环)

  • .local(本地网络)

  • code.iflytek.com(公司 Git 域名)

  • *.iflytek.com(公司所有子域名,以防万一)

于是,救命的配置诞生了:

no_proxy="localhost,127.0.0.1,.local,code.iflytek.com,*.iflytek.com"

手把手教你配置 no_proxy

根据你的操作系统和终端,配置方式略有不同。这里给出最常用的两种。

Windows (PowerShell)

如果你只是在当前终端临时使用,可以直接设置环境变量:

$env:no_proxy="localhost,127.0.0.1,.local,code.iflytek.com,*.iflytek.com"

如果想永久生效,可以通过系统环境变量设置:

  1. 打开“设置” > “系统” > “关于” > “高级系统设置”

  2. 点击“环境变量”

  3. 在“系统变量”或“用户变量”中点击“新建”,变量名输入 no_proxy,变量值输入上述字符串

  4. 确定保存,重新打开终端即可

macOS / Linux

临时生效(当前终端会话):

export no_proxy="localhost,127.0.0.1,.local,code.iflytek.com,*.iflytek.com"

永久生效:将上面的 export 命令添加到你的 shell 配置文件中,如 ~/.bashrc~/.zshrc 等,然后执行 source ~/.bashrc 使配置生效。

配置完成后,再次执行 Git 命令,世界恢复了平静:

git push origin main
Everything up-to-date

完美!

求救2:在claude code中输入命令

直接和claude说,把环境变量的代理删除,配置到他全局的setting.json中

原理浅析:为什么 no_proxy 能解决问题?

当我们执行一个需要网络连接的 Git 命令时,Git 会检查目标 URL 的主机名。如果该主机名匹配了 no_proxy 列表中的任何一项,Git 就会直接连接目标服务器,而不经过任何代理。否则,它会将请求转发给 HTTP_PROXY 或 HTTPS_PROXY 指定的代理服务器。

在我们的场景中,code.iflytek.com 命中了 no_proxy 规则,Git 直接与公司 Git 服务器建立 TLS 连接,握手正常完成,自然不会再出现“unexpected eof”。

这里有个小细节:no_proxy 支持通配符 *,例如 *.iflytek.com 可以匹配 code.iflytek.comgit.iflytek.com 等所有子域名,非常方便。另外,一些实现也支持前缀匹配,比如 .local 可以匹配任何以 .local 结尾的域名。

防患于未然:代理配置的最佳实践

这次小插曲也给我们提了个醒:在使用代理时,最好养成设置 no_proxy 的好习惯。以下是一些最佳实践:

  1. 总是配置 no_proxy:只要设置了 HTTP_PROXY,就应该同时配置 no_proxy,至少包含 localhost,127.0.0.1,.local 以及公司内网域名。

  2. 区分大小写? 通常环境变量名不区分大小写,但为了保险,可以同时设置 no_proxy 和 NO_PROXY(某些工具只认大写)。

  3. 检查当前代理设置:遇到网络问题时,先执行 echo $HTTP_PROXY 和 echo $HTTPS_PROXY,看看是否有残留的代理配置。

  4. 使用 Git 自身的代理配置:如果只想为 Git 配置代理,可以使用 Git 的全局配置,例如:

git config --global http.proxy http://proxy.example.com:port
git config --global https.proxy http://proxy.example.com:port

这种方式不会影响其他工具,而且 Git 本身也支持 http.proxy 的 no_proxy 类似功能(通过 http.proxyAuthMethod 或 http.extraHeader 等,但不如环境变量通用)。

     5.会话隔离:如果只是临时需要使用代理,可以在一个单独的终端会话中设置,用完关闭即可,避免污染全局环境。

写在最后

这次由 Claude Code 代理引发的 Git 风波,虽然让人虚惊一场,但也让我们对代理的工作机制有了更深的理解。技术世界里,每一个报错背后都藏着一个有趣的故事,而解决问题的过程,正是我们与计算机对话、理解其逻辑的过程。

下次当你再看到 TLS connect error 时,不妨先检查一下代理设置,也许 no_proxy 就是你需要的那个“钥匙”。毕竟,有时候,让某些东西“不走寻常路”,反而能更快抵达终点。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐