FTPES是显式TLS加密的FTP协议,客户端先明文连21端口再发AUTH TLS;而隐式FTPS已废弃,需直连990端口并立即SSL握手。.NET的FtpWebRequest仅支持FTPES,关键设置为EnableSsl=true、Credentials非空、UseBinary=true。

FTPES 是什么,和 FTPS 有什么区别
FTPES(FTP over Explicit SSL/TLS)是显式启用 TLS 的方式:客户端先用明文连接 FTP 服务器的 21 端口,再发送 AUTH TLS 命令协商加密;而隐式 FTPS(已基本废弃)要求一建立 TCP 连接就立刻进入 SSL 握手,使用 990 端口。.NET 的 FtpWebRequest 只支持 FTPES,不支持隐式 FTPS —— 所以你根本不用纠结“选哪个”,只要服务器开的是标准 FTPES(端口 21 + AUTH TLS),FtpWebRequest 就能用。
用 FtpWebRequest 上传文件到 FTPES 的关键设置
核心是三处布尔开关必须设对,缺一不可:
-
EnableSsl = true:告诉 .NET 启用 TLS 协商(触发AUTH TLS) -
Credentials = new NetworkCredential(...):必须提供凭据,否则EnableSsl = true会抛WebException(错误信息:The remote server returned an error: (530) Not logged in.) -
UseBinary = true:二进制模式传文件,避免换行符被误转(尤其传 zip、exe、图片时)
示例片段:
FtpWebRequest req = (FtpWebRequest)WebRequest.Create("ftp://example.com/file.txt");
req.Credentials = new NetworkCredential("user", "pass");
req.EnableSsl = true;
req.UseBinary = true;
req.Method = WebRequestMethods.Ftp.UploadFile;
using (Stream reqStream = req.GetRequestStream())
using (FileStream fileStream = File.OpenRead(@"C:\local\file.txt"))
{
fileStream.CopyTo(reqStream);
}
证书验证失败怎么办:跳过或自定义校验
默认情况下,.NET 会严格校验证书链和主机名匹配。常见报错:The remote certificate is invalid according to the validation procedure.。这不是代码写错了,而是服务器用了自签名证书、通配符不匹配,或时间不同步。
生产环境不该跳过,但测试时可临时绕过:
- 全局禁用(不推荐):
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true; - 按请求粒度控制(较安全):在创建
FtpWebRequest前,给req.ServicePoint绑定回调,只对当前域名生效 - 更稳妥的做法:实现校验逻辑,比如只接受特定指纹或固定 CN
注意:EnableSsl = true 必须在设置 ServicePoint 回调之后再赋值,否则回调可能不生效。
.NET Core / .NET 5+ 中 FtpWebRequest 的兼容性陷阱
从 .NET Core 2.1 开始,FtpWebRequest 被标记为“仅限 Windows”,Linux/macOS 上调用会直接抛 PlatformNotSupportedException。这意味着如果你部署在 Docker(Linux 容器)或 Azure App Service(Linux SKU)上,这段代码会挂掉。
替代方案只有两个现实选择:
- 改用跨平台 FTP 库,如
FluentFTP(NuGet 包FluentFTP),它原生支持 FTPES、主动/被动模式、自定义证书验证,API 也比原生更直观 - 坚持用原生?只能限定部署在 Windows Server 或 Windows Container 上,并确保目标框架是
net6.0-windows或更高
FluentFTP 示例只需两行启 FTPES:
using (var client = new FtpClient("example.com", "user", "pass"))
{
client.EncryptionMode = FtpEncryptionMode.Explicit;
client.UploadFile(@"C:\local\file.txt", "/remote/file.txt");
}
真正容易被忽略的是:被动模式(PASV)下,FTPES 的数据通道也要加密,而 FtpWebRequest 会自动处理,但 FluentFTP 需显式设 DataConnectionType = FtpDataConnectionType.AutoActive 或依赖服务器配置 —— 这类细节不看文档很容易传一半卡住。










