解决:MalformedServerReplyException: Could not parse response code. Server Reply: SSH-2.0-OpenSSH 异常。
场景:
Java后台使用org.apache.commons.net.ftp.FTPClient 连接服务器,进行FTP操作 :上传/下载文件。
异常:
org.apache.commons.net.MalformedServerReplyException: Could not parse response code.
Server Reply: SSH-2.0-OpenSSH
at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:337)
at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:294)
at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:400)
at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:924)
at org.apache.commons.net.SocketClient.connect(SocketClient.java:183)
at org.apache.commons.net.SocketClient.connect(SocketClient.java:203)
at com.web.util.FtpUtil.connectFTP(FtpUtil.java:351)
at com.web.util.FtpUtil.main(FtpUtil.java:375)
nullProcess finished with exit code 0
原因:
一般我们使用 Xftp 或 FileZilla这些软件去连接服务器(FTP/SFTP)都是可以连接到。区别就是连接的参数中
1.协议:ftp 或 sftp
2.端口:21/22
但是在Java后台使用org.apache.commons.net.ftp.FTPClient通过协议SSH2进行SFTP连接时就会报如上错误,原因是它不支持这种方式的连接(使用FTPSClient的SSL也是不行的)。
解决方法有两种:
第一种:Java后台继续使用org.apache.commons.net.ftp.FTPClient工具,然后把服务器开启FTP协议。
第二种:换一种连接方式,使用 com.jcraft.jsch.ChannelSftp 代替org.apache.commons.net.ftp.FTPClient。
使用第二种需要引入 com.jcraft.jsch.ChannelSftp 架包。SpringBoot项目在pom中直接引入,其他的可自行下载。
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.49</version>
</dependency>
使用第一种方法需要找运维去把服务器开启SFTP协议,一般你个小开发人家能不能帮你或者基于一些安全考虑能不能开启都是问题。所以这里推荐使用第二种方法。
ChannelSftp 和 FTPClient 的一些使用中区别:
1、连接方式
FTPClient的连接
FTPClient ftp = new FTPClient();
ftp.connect(ip, port);
//下面三行代码必须要,而且不能改变编码格式
ftp.setControlEncoding("UTF-8");
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
conf.setServerLanguageCode("zh");
//如果采用默认端口,可以使用ftp.connect(url) 的方式直接连接FTP服务器
ftp.login(userName, password);//登录
ChannelSftp 连接
JSch jsch = new JSch();
if (privateKey != null) {
jsch.addIdentity(privateKey);// 设置私钥
}
Session session = jsch.getSession(userName, host, port);
if (password != null) {
session.setPassword(password);
}
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftp = (ChannelSftp) channel;
2、主要功能方法
切换到 directory 目录:ChannelSftp.cd(directory); FtpClient.changeWorkingDirectory(ftpFilePath);
上传文件:ChannelSftp.put(FileInputStream, fileName) ; FtpClient.storeFile(fileName, FileInputStream);
下载文件:ChannelSftp.get(fileName, new FileOutputStream(file)); FtpClient.retrieveFileStream() 或 FtpClient.retrieveFile
还有需要注意的就是关闭的连接的方法,ChannelSftp需要你把 Session也关闭掉。