FtpWebRequest 因主动模式兼容性差、无异步支持等缺陷已被弃用,应改用 FluentFTP;必须设 UsePassive=true、KeepAlive=false、显式超时,并用相对路径;WebClient 需将凭据嵌入 URI 且已过时。

FtpWebRequest 是 C# 里最直接、最可控的 FTP 下载方式,但别急着用它——.NET 6+ 新项目优先考虑 WebClient(已过时但仍可用)或改用第三方库(如 FluentFTP),因为原生 FtpWebRequest 有严重缺陷:不支持异步流式下载、SSL/TLS 配置反直觉、超时逻辑混乱,且已在 .NET Core 3.0+ 中被标记为“不推荐使用”。
为什么 FtpWebRequest 下载常卡住或报 550 错误
根本原因不是路径写错,而是它默认以“主动模式(Active Mode)”连接服务器,而绝大多数现代网络(NAT、防火墙、云主机)会拦截服务端发起的回连。结果就是连接 hang 住,或返回 550 File unavailable(实际是控制通道能通,数据通道失败)。
实操建议:
- 强制设为被动模式:
request.UsePassive = true;(必须在GetResponse()前设置) - 关闭默认的 KeepAlive:
request.KeepAlive = false;,避免连接复用引发状态残留 - 显式设置超时:
request.Timeout = 30_000;和request.ReadWriteTimeout = 30_000;,否则默认是 -1(无限等待) - 路径必须是服务器上的**相对路径**,且不能以
/开头(比如files/report.zip✅,/files/report.zip❌)
用 WebClient 快速下载但要注意凭据陷阱
WebClient 看似简单,但它的 Credentials 属性只对 BASIC 认证有效;如果 FTP 服务器要求明文账号密码(常见于 Pure-FTPd、vsftpd 默认配置),必须用 NetworkCredential 并拼进 URL:
var client = new WebClient();
client.Credentials = new NetworkCredential("user", "pass");
// ⚠️ 错误:client.DownloadFile("ftp://host/file.zip", "local.zip");
// ✅ 正确(把凭据嵌入 URI):
client.DownloadFile("ftp://user:pass@host/files/data.txt", "data.txt");注意点:
- URL 中的用户名密码会被 URI 编码,特殊字符(如
@、/)必须先Uri.EscapeDataString() -
WebClient在 .NET 5+ 已标记为 obsolete,仅限快速原型或遗留维护 - 无法控制被动/主动模式,底层仍走
FtpWebRequest,所以同样受防火墙限制
推荐方案:用 FluentFTP 替代原生类库
这是目前最活跃、文档最清晰的 .NET FTP 库,NuGet 安装:Install-Package FluentFTP。它默认启用被动模式、自动重试、支持异步、SSL 显式开关,且错误信息具体(比如明确告诉你“无法建立数据连接”,而非笼统的 550)。
最小可行下载示例:
using (var ftp = new FtpClient("host", "user", "pass")) {
ftp.Connect();
using (var stream = ftp.OpenRead("/remote/file.log"))
using (var file = File.Create("local.log"))
await stream.CopyToAsync(file);
}关键配置项:
- 启用 TLS:
ftp.EncryptionMode = FtpEncryptionMode.Explicit;(对应 FTPS) - 跳过证书验证(仅测试用):
ftp.ValidateCertificate += (c, e) => e.Accept = true; - 设置超时:
ftp.ReadTimeout = 30000;、ftp.DataConnectionConnectTimeout = 15000; - 若仍连不上,尝试
ftp.DataConnectionType = FtpDataConnectionType.PASV;(虽然默认就是 PASV)
真正麻烦的从来不是“怎么写几行代码”,而是 FTP 协议本身在不同服务器、不同网络环境下的行为差异——比如某些 vsftpd 配置下,PASV 返回的 IP 是内网地址,必须配 pasv_address;又比如 IIS FTP 的目录列表格式和 Unix 类服务器完全不同,会影响路径解析。动手前,先用 FileZilla 连一下,看它用的是主动还是被动、是否启用了加密、目录结构是否和你写的路径一致。


















