ftpwebrequest在.net 6+中已过时且跨平台不可靠,根本原因在于其依赖windows网络栈、pasv模式解析僵硬、不支持隐式ftps及utf-8路径,易致超时、乱码、零字节上传等问题;推荐改用fluentftp。

FtpWebRequest 在 .NET 6+ 中已标记为过时(obsolete),且在跨平台场景下行为不可靠;不建议新项目使用,尤其遇到超时、被动模式失败、中文路径乱码或大文件传输中断时,几乎必然踩坑。
为什么 FtpWebRequest 经常上传失败或卡死
根本原因在于它底层依赖 Windows 网络栈,对 PASV 模式解析僵硬,无法自动处理防火墙/NAT 后的端口映射,且不支持现代 FTPS 的隐式加密(仅支持显式 FTPSSL,但需手动处理证书验证逻辑)。
常见现象包括:
-
WebException: The operation has timed out(尤其在 LIST 或上传大文件时) - 上传后文件大小为 0 字节,无报错
-
500 Illegal PORT command或425 Can't open data connection - 中文文件名变成
%E4%BD%A0%E5%A5%BD或直接抛出UriFormatException
用 FluentFTP 替代:三步完成稳定上传下载
这是目前最活跃、文档清晰、默认启用智能被动模式和 UTF-8 路径支持的开源库。NuGet 安装后即可开用:
dotnet add package FluentFTP
基础上传示例(带重试和进度回调):
using (var client = new FtpClient("ftp.example.com", "user", "pass"))
{
client.EncryptionMode = FtpEncryptionMode.Explicit; // 显式 FTPS
client.DataConnectionType = FtpDataConnectionType.PASV; // 强制被动模式
client.Connect();
// 上传本地 file.txt 到服务器 /upload/
await client.UploadFileAsync("file.txt", "/upload/file.txt",
FtpExists.Overwrite,
createRemoteDir: true);
// 下载并监听进度
await client.DownloadFileAsync("remote.zip", "local.zip",
progress: (obj, e) => Console.WriteLine($"Progress: {e.Progress}%"));
}
关键配置点:
- 务必设
DataConnectionType = PASV,多数云 FTP(如 vsftpd、Pure-FTPd)默认只开 PASV - 若服务器要求 TLS 1.2+,加
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; - 中文路径无需编码——
FluentFTP默认启用client.Encoding = System.Text.Encoding.UTF8; - 超时控制:设
client.ReadTimeout = 30000;和client.DataConnectionConnectTimeout = 15000;
遇到“421 Too many connections”怎么办
这不是代码问题,是 FTP 服务器连接数限制触发了保护机制。常见于循环调用上传/下载却未显式断开连接。
正确做法:
- 每个操作用
using块包裹,确保Dispose()被调用(会触发Disconnect()) - 避免复用同一个
FtpClient实例做大量短连接操作;改用连接池(FtpClient本身不内置池,可自行封装ConcurrentBag<ftpclient></ftpclient>) - 检查服务器配置:
max_clients(vsftpd)、MaxClients(ProFTPD) - 临时绕过:上传前加
await client.Noop();保活,比反复新建连接更轻量
真正麻烦的从来不是“怎么传”,而是“传完没”。比如服务器返回 226 表示传输结束,但实际文件可能还在磁盘缓冲区未落盘——这时候立刻去下载,就可能拿到截断内容。生产环境必须加校验(如服务端返回 MD5 或客户端计算 SHA256 对比),这点 FtpWebRequest 和 FluentFTP 都不自动做,得自己补。











