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

问题描述

试图通过 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,aes128-ctr
o.a.c.v.provider.sftp.SftpClientFactory  : kex: server: aes256-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-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-nistp521
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: aes128-ctr,3des-cbc,blowfish-cbc,aes256-ctr,aes256-cbc
o.a.c.v.provider.sftp.SftpClientFactory  : kex: client: aes128-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-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$2.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)实现了代码并得到了更好的错误消息:“错误:3 权限被拒绝”,发现用户仅具有查看和列出文件的权限,并且没有下载权限。将用户更改为具有下载权限的用户解决了我的问题。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...