深入解析 curl Connection #0 to host … left intact 提示与损坏 zip 的根源
只是 curl 的常规告知,并不代表失败;真正导致压缩包损坏的根源,在于重定向过程中鉴权头丢失、错误页被当作 zip 写盘、或下载被意外中断。遵循上文五条实践,加上--fail--retry、哈希校验等防御措施,可以让任何自动化脚本都能在高延迟或者跳转繁多的网络环境中安全下载二进制文件。
在 Windows 终端里执行 curl -H \Authorization: Basic MDA2Rw== [https://www.baidu.com/1.zip](https://www.baidu.com/1.zip) -L -o C:\temp\file.zip --verbose时,光标停留在一行* Connection #0 to host [www.baidu.com](http://www.baidu.com/) left intact,随后得到一个无法解压的 zip。这一现象乍看像网络故障,其实它背后牵涉到 HTTP 重定向、连接复用、响应完整性校验以及 Windows shell 对路径与字符的处理。下文将沿着一次典型下载动作的时间线,逐段剖析信息流与控制流,找出压缩包损坏的真正原因,并给出可验证的修复方案。
连接生命周期与 curl 的 verbose 输出
-
libcurl 在建立 TCP 连接后,向终端写入
* Trying <ip>…、* Connected to <host> (ip)等行,它们只是日志而非错误,方便定位握手阶段的瓶颈。([stackoverflow.com](https://stackoverflow.com/questions/55310318/how-to-fix-connection-0-to-host-left-intact-in-php?utm_source=chatgpt.com “How to fix “Connection #0 to host left intact” in PHP”? - Stack Overflow"), [stackoverflow.com](https://stackoverflow.com/questions/61880928/what-does-connection-0-to-host-example-com-left-intact-mean?utm_source=chatgpt.com “what does “* Connection #0 to host example.com left intact” mean?”)) -
当后续请求仍可能复用相同 socket 时,libcurl 会记录
* Connection #0 to host <name> left intact。这句话表示句柄里的连接对象没有被立即关闭,而被放回连接池等待复用;如果命令一次只取一个 URL,这条信息可忽略,因为进程结束时操作系统仍会回收 socket。([stackoverflow.com](https://stackoverflow.com/questions/61880928/what-does-connection-0-to-host-example-com-left-intact-mean?utm_source=chatgpt.com “what does “* Connection #0 to host example.com left intact” mean?”), curl.se) -
该提示本身不会导致 zip 损坏;真正的危险在于:若服务器返回非预期内容(例如 HTML 报错页),curl 仍然会把字节流写进
file.zip,Windows 解压器再据此报错。(serverfault.com, forum.dfinity.org)
重定向与授权:两条暗线交织
HTTP 3xx 链条与 -L
浏览器或 curl 遇到 30x 响应就会跟随 Location 头发起下一跳请求。手动指定 -L 能让 curl 自动完成跳转。若跳转目标并非真实 zip,而是登陆页或 403 提示,结果写盘仍是 HTML。(stackoverflow.com, stackoverflow.com)
Basic Authorization 与失效 token
你在命令里硬编码了 Authorization: Basic MDA2Rw==;若该 token 仅被第一跳接受,而重定向后的域名、路径或协议不同,后续跳转可能丢失 Authorization,导致目标服务器改用匿名模式返回错误页。Stack Overflow 上多次出现 curl -H \Authorization: …`` 却下载到登陆页 HTML 的案例,即因重定向剥离了授权头。(stackoverflow.com, [community.atlassian.com](https://community.atlassian.com/forums/Bamboo-questions/API-response-contains-quot-Connection-0-bamboo-lt-companyname-gt/qaq-p/2002844?utm_source=chatgpt.com "Solved: API response contains “* Connection #0 bamboo.<com…”))
为什么到手的 zip 打不开
-
文件内容为 HTML
打开file.zip以文本方式查看,若首行是<!DOCTYPE html>或包含<html>,即可判定这是错误页而非二进制 zip。([unix.stackexchange.com](https://unix.stackexchange.com/questions/686378/curl-downloads-zip-file-as-ascii-text-zipfile-is-not-corrupted?utm_source=chatgpt.com ““curl” downloads .zip file as ASCII text (zipfile is not corrupted!)”), stackoverflow.com) -
下载被截断
某些 CDN 会在请求体超过阈值时中断连接;又因为你没有--retry或--continue-at, libcurl 直接写一个半截文件到磁盘。下一次调用 7-Zip 时解压器会提示Unexpected end of archive。(curl.se) -
Windows shell 字符转义
在 PowerShell 中,把路径包进双引号时若含有反斜杠结尾,可能被解释成转义符;C:\temp\file.zip没问题,但若用户改写为C:\temp\new\file.zip`` 会触发转义,生成空文件。(askubuntu.com)
逐步定位与自我验证
检查 HTTP 头与响应
curl -H `Authorization: Basic MDA2Rw==` https://www.baidu.com/1.zip \
-L -w `\nHTTP_CODE=%{http_code}\nREDIR=%{redirect_url}\nSIZE=%{size_download}\n` \
-o C:\temp\file.zip --verbose --fail
-
--fail一旦最终响应码≥400 就退出并返回 22,避免把错误页写进 zip。(superuser.com, stackoverflow.com) -
-w让 curl 在完成后打印 HTTP 码、最终 URL 与实际下载字节数;如果看到HTTP_CODE=200但SIZE明显小于 Content-Length,说明下载被截断。
对比响应类型
curl -I -H `Authorization: Basic MDA2Rw==` https://www.baidu.com/1.zip
- 期望得到
Content-Type: application/zip;若返回text/html,说明服务端并未输出二进制文件,而是跳转或错误页。(stackoverflow.com)
校验文件哈希
Get-FileHash C:\temp\file.zip -Algorithm MD5
将输出与服务器提供的 MD5 校验和对比即可判定完整性。
保障完整下载的几条实践
-
用
--remote-name搭配--remote-header-name,让 curl 依据Content-Disposition自动定名,减少误写入路径的机会。 -
保留授权头穿越重定向:添加
--location-trusted让 curl 在每次跳转时保留机密头部;或者把 token 放进 URL 查询串以规避头部丢失(前提是后端允许)。 -
断点续传与重试:
--retry 3 --retry-delay 2 --continue-at -在网络抖动场景下能显著降低损坏概率。 -
确认 MIME 与大小:脚本里解析
Content-Type与Content-Length,不匹配就立刻rm file.zip && exit 1。 -
*Windows 与 nix 行为差异:在 CMD 用
^转义,在 PowerShell 用"反引号` 转义参数,避免路径被截断。(devops.stackexchange.com)
参考脚本范例(可直接运行)
$Url = 'https://www.baidu.com/1.zip'
$Token = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('user:pass'))
$OutFile = 'C:\temp\file.zip'
$Header = "Authorization: Basic $Token"
$retry = 0
do {
$retry++
curl -H "`$Header" $Url -L --location-trusted --fail --retry 3 `
--retry-delay 2 --connect-timeout 10 `
--output "$OutFile.part"
if ($LASTEXITCODE -eq 0) {
Move-Item "$OutFile.part" $OutFile -Force
$hash = (Get-FileHash $OutFile -Algorithm SHA256).Hash
Write-Host "Download succeeded, SHA256=$hash"
break
} else {
Write-Host "Attempt $retry failed, retrying…"
}
} until ($retry -ge 3)
上述脚本:
-
使用
$OutFile.part作为临时文件,失败时不会污染旧文件; -
--location-trusted保留 Authorization 直至最后一跳; -
利用
Get-FileHash即时校验确保 zip 完整。
结语
Connection #0 to host … left intact 只是 curl 的常规告知,并不代表失败;真正导致压缩包损坏的根源,在于重定向过程中鉴权头丢失、错误页被当作 zip 写盘、或下载被意外中断。遵循上文五条实践,加上 --fail、--retry、哈希校验等防御措施,可以让任何自动化脚本都能在高延迟或者跳转繁多的网络环境中安全下载二进制文件。
更多推荐



所有评论(0)