5月28日 01:53

cURL 和 wget 有什么区别?

cURL 和 wget 是 Linux 系统中最常用的两个命令行网络工具,面试中经常被放在一起考察。很多候选人只能说出"cURL 能测 API,wget 能递归下载",但这远远不够。这道题的真正考点在于理解两个工具的设计哲学差异以及底层架构不同如何决定了它们各自的适用场景。

一句话概括核心区别

cURL 是网络传输的瑞士军刀,wget 是文件下载的可靠管家。

cURL 的设计目标是做一个通用的数据传输工具——它不关心你传什么、怎么传,只管把数据从 A 搬到 B。wget 的设计目标是可靠地下载文件——网络断了自动重试,链接坏了自动转换,一切都为了让文件安稳落地。

这个底层设计哲学的差异,直接导致了两者在协议支持、功能特性和使用场景上的全面分歧。

核心差异对比

维度cURLwget
设计目标通用数据传输可靠文件下载
底层架构基于 libcurl 库独立程序,无库形式
协议支持20+ 种(HTTP/1.1、HTTP/2、HTTP/3、FTP、SFTP、SCP、SMTP、LDAP 等)HTTP/HTTPS/FTP
数据方向双向(上传 + 下载)单向(仅下载)
递归下载不支持支持,可镜像整站
并行传输支持(7.66+ 版本 -Z 参数)不支持
后台下载需配合 nohup原生支持 -b
输出方式默认输出到 stdout默认保存为文件
重定向处理需手动加 -L自动跟随
库集成libcurl 可嵌入应用程序无库形式,无法嵌入

协议支持:为什么 cURL 能做 wget 做不了的事

cURL 支持超过 20 种协议,这意味着它不仅是 HTTP 客户端,还能发送邮件、操作 LDAP 目录、通过 SFTP/SCP 传输文件:

bash
# 通过 SMTP 发送邮件 curl smtp://mail.example.com --mail-from sender@test.com --mail-rcpt receiver@test.com -T mail.txt # SFTP 上传文件(wget 完全不支持上传) curl -T backup.tar.gz sftp://user@host.example.com/backup/ # 查询 LDAP 目录 curl ldap://ldap.example.com/cn=admin,dc=example,dc=com

wget 只支持 HTTP/HTTPS/FTP 三种协议。这不是偷懒,而是设计上的取舍——专注做好下载这一件事。

递归下载:wget 的杀手级特性

递归下载是 wget 独有的能力,也是它和 cURL 最大的功能分界线:

bash
# 镜像整个网站(最常用的递归下载场景) wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://example.com/docs/ # 从文件列表批量下载 wget -i download-urls.txt # 限定深度递归 wget --recursive --level=2 --no-parent https://example.com/data/

cURL 无法递归下载。如果你需要对网站做离线备份、数据抓取或批量归档,wget 是唯一的选择。

API 交互:cURL 的主场

cURL 在 API 开发测试领域几乎是事实标准。大多数 API 文档的示例代码都用 cURL 编写,这不是偶然:

bash
# 发送 JSON 请求 curl -X POST https://api.example.com/users -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9" -d '{"name":"test","role":"admin"}' # 只看响应头(调试必备) curl -I https://api.example.com/health # 提取 HTTP 状态码(脚本判断用) curl -s -o /dev/null -w "%{http_code}" https://api.example.com/status

wget 虽然也能发 POST 请求(--post-data),但不支持自定义请求方法、无法设置复杂 Header、不能方便地查看响应细节,在实际 API 调试中几乎不可用。

底层架构差异:libcurl vs 独立程序

这是面试中能拉开差距的知识点。

cURL 基于 libcurl 库。libcurl 是一个成熟的跨平台 C 库,提供了稳定的 API 接口,几乎所有主流编程语言都有对应的绑定(Python 的 pycurl、PHP 的 curl 扩展、Node.js 的 node-libcurl 等)。这意味着你在代码中用这些库发 HTTP 请求时,底层跑的就是 libcurl,和命令行的 cURL 是同一套实现。

wget 没有库形式。它是一个独立的命令行程序,无法嵌入到应用程序中。如果你需要在代码中实现下载功能,要么自己写 HTTP 逻辑,要么用 libcurl。

bash
# 验证:Python 的 requests 库底层不是 libcurl # 但 pycurl 是 libcurl 的 Python 绑定 import pycurl # 底层就是 libcurl

这个架构差异也解释了为什么 Docker 官方镜像和大多数 CI/CD 环境预装的是 cURL 而不是 wget——因为很多构建工具依赖 libcurl。

现代特性对比

cURL 在持续演进,许多现代特性 wget 尚不支持:

特性cURLwget
HTTP/2支持(--http2不支持
HTTP/3 (QUIC)支持(--http3不支持
并行传输支持(-Z不支持
自动解压gzip/brotli/zstdgzip
SOCKS 代理SOCKS4/SOCKS5不支持
多种认证Basic/Digest/NTLM/AWS v4Basic/Digest

生产环境中的常见坑

坑 1:cURL 不自动跟随重定向

很多 API 会返回 301/302 重定向,cURL 默认不会跟随,导致你以为请求失败了:

bash
# 错误:返回 301 但不跳转 curl https://example.com/old-api # 正确:加 -L 跟随重定向 curl -L https://example.com/old-api

wget 默认自动跟随重定向,不需要额外参数。

坑 2:wget 下载大文件磁盘不够

wget 默认行为是直接把响应写入文件,如果磁盘空间不足会下载失败且留下不完整的文件:

bash
# 先检查文件大小再决定是否下载 wget --spider https://example.com/huge-file.zip 2>&1 | grep Length

坑 3:cURL 在脚本中不检查 HTTP 错误码

cURL 默认不会因为 4xx/5xx 而返回非零退出码,这在脚本中容易漏掉错误:

bash
# 错误:脚本不会因 404 而中断 curl https://api.example.com/not-exist # 正确:加 --fail 让 4xx/5xx 返回非零退出码 curl --fail https://api.example.com/not-exist

坑 4:Docker 构建中用 wget 代替 cURL

某些精简 Docker 镜像没有预装 cURL,有人会改用 wget 测试连通性。但 wget 的输出格式不同,且不支持 -I(只看头部),推荐在 Dockerfile 中安装 cURL:

dockerfile
RUN apt-get update && apt-get install -y curl --no-install-recommends

面试回答模板

简短版(30 秒):

cURL 是通用网络传输工具,支持 20+ 协议,基于 libcurl 库可嵌入应用,擅长 API 交互和双向数据传输;wget 是专注文件下载的工具,支持递归下载和网站镜像,擅长批量下载和后台任务。选 cURL 做接口调试和脚本自动化,选 wget 做文件下载和站点归档。

详细版(2 分钟):

在简短版基础上补充三点:一是底层架构差异,cURL 基于 libcurl 库可被程序调用,wget 是独立程序无法嵌入;二是现代特性,cURL 已支持 HTTP/2、HTTP/3 和并行传输,wget 在协议层面更新较慢;三是常见陷阱,比如 cURL 不自动跟随重定向需要加 -L,以及 --fail 参数在脚本中的重要性。

选择决策速查

场景推荐原因
API 开发调试cURL方法/头部/认证灵活可控
简单文件下载两者皆可wget 更直觉,cURL 更可控
网站离线镜像wget递归下载能力不可替代
多协议传输cURL支持 SFTP/SCP/SMTP 等
脚本自动化cURL输出灵活,适合管道处理
批量下载wget-i 参数支持从文件读 URL
Docker/CI 环境cURL预装率高,libcurl 被广泛依赖
后台无人值守下载wget-b 原生后台支持

实际工作中两者都应掌握。cURL 更适合开发者的日常交互,wget 更适合运维的批量下载场景。如果只能装一个,选 cURL——它的能力范围更广,且 libcurl 是很多工具链的底层依赖。

标签:cURL