使用 Apache Commons vfs2(spring boot) 的 SFTP 文件传输因 IOException: 错误而失败

SFTP file transfer using Apache Commons vfs2(spring boot) fails with IOException: error

正在尝试通过 sftp 将文件从一台远程主机传输到另一台。

sftp 依赖项:

 implementation 'org.apache.commons:commons-vfs2:2.4'

 compile 'com.jcraft:jsch:0.1.55'

运行 AWS EKS Kubernetes pod 中的代码可以访问两个远程主机(因为连接成功)。 在 Kubernetes pod 中遇到以下错误:

日志

o.a.c.v.provider.sftp.SftpClientFactory  : Connecting to host port 22
o.a.c.v.provider.sftp.SftpClientFactory  : Connection established
o.a.c.v.provider.sftp.SftpClientFactory  : Remote version string: SSH-2.0-JSCAPE
o.a.c.v.provider.sftp.SftpClientFactory  : Local version string: SSH-2.0-JSCH-0.1.54
o.a.c.v.provider.sftp.SftpClientFactory  : CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256
o.a.c.v.provider.sftp.SftpClientFactory  : CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
o.a.c.v.provider.sftp.SftpClientFactory  : CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_KEXINIT sent
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_KEXINIT received
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: diffie-hellman-group14-sha256,diffie-hellman-group-exchange-sha256
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: ssh-rsa,rsa-sha2-256,rsa-sha2-512
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: aes256-ctr,aes192-ctr,aes128-ctr
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: aes256-ctr,aes192-ctr,aes128-ctr
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: hmac-sha1,hmac-sha2-512
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: hmac-sha1,hmac-sha2-512
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: none
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: none
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: 
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: 
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: none
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: none
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: 
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: 
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server->client aes128-ctr hmac-sha1 none
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client->server aes128-ctr hmac-sha1 none
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_KEX_DH_GEX_REQUEST(1024<2048<2048) sent
o.a.c.v.provider.sftp.SftpClientFactory  : expecting SSH_MSG_KEX_DH_GEX_GROUP
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_KEX_DH_GEX_INIT sent
o.a.c.v.provider.sftp.SftpClientFactory  : expecting SSH_MSG_KEX_DH_GEX_REPLY
o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
o.s.web.servlet.DispatcherServlet        : Completed initialization in 47 ms
o.a.c.v.provider.sftp.SftpClientFactory  : ssh_rsa_verify: signature true
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_NEWKEYS sent
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_NEWKEYS received
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_SERVICE_REQUEST sent
o.a.c.v.provider.sftp.SftpClientFactory  : SSH_MSG_SERVICE_ACCEPT received
o.a.c.v.provider.sftp.SftpClientFactory  : Authentications that can continue: publickey,keyboard-interactive,password
o.a.c.v.provider.sftp.SftpClientFactory  : Next authentication method: publickey
o.a.c.v.provider.sftp.SftpClientFactory  : Authentications that can continue: password
o.a.c.v.provider.sftp.SftpClientFactory  : Next authentication method: password
o.a.c.v.provider.sftp.SftpClientFactory  : Authentication succeeded (password).
m.j.r.utils.helper.FileTransferHelper    : FileTransferFailed due to IOException:
org.apache.commons.vfs2.FileSystemException: Could not copy "sftp://username:***@host/fileWithPath" to "file:///tmp/ImpFile".
    at org.apache.commons.vfs2.provider.AbstractFileObject.copyFrom(AbstractFileObject.java:300) ~[commons-vfs2-2.4.jar:2.4]
    at my.package.name.utils.helper.FileTransferHelper.transferFile(FileTransferHelper.java:39) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:305) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:190) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:153) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:403) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:360) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.boot.context.event.EventPublishingRunListener.running(EventPublishingRunListener.java:103) ~[spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.boot.SpringApplicationRunListeners.running(SpringApplicationRunListeners.java:77) ~[spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:330) ~[spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at money.jupiter.reporting.ReportingApplication.main(ReportingApplication.java:17) ~[classes/:na]
 Caused by: java.io.IOException: error
    at com.jcraft.jsch.ChannelSftp.read(ChannelSftp.java:1448) ~[jsch-0.1.55.jar:na]
    at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[na:na]
    at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[na:na]
    at org.apache.commons.vfs2.util.MonitorInputStream.read(MonitorInputStream.java:106) ~[commons-vfs2-2.4.jar:2.4]
    at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:252) ~[na:na]
    at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:292) ~[na:na]
    at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[na:na]
    at org.apache.commons.vfs2.util.MonitorInputStream.read(MonitorInputStream.java:106) ~[commons-vfs2-2.4.jar:2.4]
    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:na]
    at org.apache.commons.vfs2.provider.DefaultFileContent.write(DefaultFileContent.java:804) ~[commons-vfs2-2.4.jar:2.4]
    at org.apache.commons.vfs2.provider.DefaultFileContent.write(DefaultFileContent.java:784) ~[commons-vfs2-2.4.jar:2.4]
    at org.apache.commons.vfs2.provider.DefaultFileContent.write(DefaultFileContent.java:755) ~[commons-vfs2-2.4.jar:2.4]
    at org.apache.commons.vfs2.provider.DefaultFileContent.write(DefaultFileContent.java:771) ~[commons-vfs2-2.4.jar:2.4]
    at org.apache.commons.vfs2.FileUtil.copyContent(FileUtil.java:37) ~[commons-vfs2-2.4.jar:2.4]
    at org.apache.commons.vfs2.provider.AbstractFileObject.copyFrom(AbstractFileObject.java:295) ~[commons-vfs2-2.4.jar:2.4]
    ... 22 common frames omitted

代码

  private static void transferFile(String sourceFile, String destinationFile, boolean overWrite) {
    try {
      var fileSystemManager = VFS.getManager();
      try (var destinationFileObject = fileSystemManager.resolveFile(destinationFile)) {
        try (var sourceFileObject = fileSystemManager.resolveFile(sourceFile)) {
          if (!overWrite && destinationFileObject.exists()) {
            log.error("file already exists and overWrite is disabled");
            throw new ReportingException(FILE_ALREADY_EXISTS);
          }
          destinationFileObject.copyFrom(sourceFileObject, Selectors.SELECT_SELF);
        }
      }
    } catch (IOException ex) {
      log.error("FileTransferFailed due to IOException:", ex);
      throw new ReportingException(FILE_TRANSFER_FAILED);
    }
  }
}

基于此行(ChannelSftp.java:1448) 从错误查看“ChannelSftp”文件,发现当“header.type”设置为 101(SSH_FXP_STATUS), 但在那之后没有找到线索。

(当 运行 从我的笔记本电脑下载免费 SFTP 服务器中可用的文件时,它在我组织的测试版系统 LINK of free SFTP server 中给了我这个问题)

我尝试在复制前使用“if(sourceFileObject.isReadable())”执行可读性检查,但执行在这一行停止,既不继续也不显示超时。

欢迎提供任何帮助。

我使用不同的库(仅使用 jcraft:jsch 而不是 vfs2)实现了代码并得到了更好的错误消息:“error:3 permission denied”,发现用户仅具有查看权限并列出文件,没有下载权限。将用户更改为具有下载权限的用户解决了我的问题。