ftplib.FTP_TLS连接失败主因是证书验证、PASV模式配置不当、编码不一致及传输模式错误;应分别关闭校验(测试用)、配置公网PASV地址、设置ftp.encoding="utf-8"、非文本文件必用storbinary,并上传后校验大小。

ftplib.FTP_TLS 连接失败:证书验证报错怎么处理
直接用 ftplib.FTP_TLS 会卡在 SSL 握手,常见报错是 ssl.SSLCertVerificationError 或 ftplib.error_perm: 534 Policy requires SSL.——不是你密码错了,是默认启用了证书校验,而多数企业 FTP 服务器用的是自签名证书或过期证书。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先尝试关闭证书验证:
ftp = ftplib.FTP_TLS()后立刻调用ftp.ssl_context.check_hostname = False和ftp.ssl_context.verify_mode = ssl.CERT_NONE(注意要 import ssl) - 更稳妥的做法是加载可信根证书或指定服务器证书路径,用
ssl.create_default_context(cafile="path/to/cert.pem")赋给FTP_TLS(context=...) - 别在生产环境长期关验证;测试通过后,优先推动运维更新有效证书,而不是写死绕过逻辑
上传文件时卡住或中断:被动模式(PASV)没配对
FTP over TLS 下,PASV 模式容易被防火墙/NAT 拦截,尤其在云主机或 Docker 容器里——客户端发了 PASV 命令,服务器返回的 IP 是内网地址(如 172.18.0.3),客户端连不上,就一直挂在那里,无报错也无进度。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 强制禁用 PASV,改用主动模式(PORT):
ftp.set_pasv(False),但需确保客户端能从随机高位端口连回服务器(通常不现实) - 更常用的是保留 PASV,但让服务器返回公网 IP:
ftp.sendcmd("EPSV")或配置服务器端的pasv_address(如 vsftpd 的pasv_address=your.public.ip) - 上传大文件前加超时:
ftp = ftplib.FTP_TLS(timeout=60),避免无限等待
中文文件名乱码或 550 错误:编码没对齐
FTP 协议本身不定义字符集,ftplib 默认用系统 locale 编码传文件名。Linux 服务器用 UTF-8,Windows 客户端可能是 gbk,一传就变 ?????.txt,或者直接报 550 Could not delete file: No such file or directory(其实是找错了名)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 显式设置传输编码:
ftp.encoding = "utf-8"(Python 3.9+ 支持;旧版本需 monkey patchftp.sendcmd或改源码) - 上传前手动编码再解码一次:
filename.encode("utf-8").decode("latin-1")是常见 hack,但仅适用于 ASCII 子集;稳妥做法是统一服务端和客户端都用 UTF-8,并确认 FTP 服务支持OPTS UTF8 ON - 避免中文文件名——真要支持,优先走 SFTP(paramiko),FTP 本质不适合多语言场景
上传完成但文件大小为 0:二进制模式没切对
storbinary() 和 storlines() 看似只差一个字母,但影响巨大。用 storlines() 传 zip、pdf、exe,内容会被自动换行符替换(CRLF → LF),导致校验失败、解压报错、甚至文件损坏为 0 字节。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 所有非纯文本文件(图片、压缩包、可执行文件等)必须用
ftp.storbinary(f"STOR {remote_path}", open(local_path, "rb")) - 纯文本且确认换行一致(如只在 Linux 环境流转)才考虑
storlines();否则一律 binary - 上传后加校验:
ftp.size(remote_path)对比本地os.path.getsize(local_path),不等就重传
真正麻烦的不是连不上,而是连上了、传完了、看着成功了,结果文件打不开——这种问题往往发生在跨平台、跨网络、跨编码的组合场景里,得一项项排除,不能靠“应该没问题”跳过验证。


















