使用Spring Integration SFTP上传文件时写入失败问题求助
Spring Integration SFTP上传失败(No such file)
问题场景
为测试需求,使用Docker部署emberstack/sftp作为SFTP服务器,容器配置如下:
sftp: image: emberstack/sftp volumes: - ./data/sftp.json:/app/config/sftp.json:ro - ./data/sftptest:/home/demo/sftp:rw ports: - "2222:22"
基于Spring Boot 2.7.4/Kotlin Coroutines/Java 17,通过Spring Integration实现SFTP上传,核心代码如下:
配置类:
@Configuration // 修正原代码拼写错误:@Confgiuration -> @Configuration class MyConfig{ // 其他Bean定义 @Bean fun sftpOutboundFlow(): IntegrationFlow { return IntegrationFlows .from("toSftpChannel") .handle( Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL) .useTemporaryFileName(false) .remoteDirectory(sftpProperties.remoteDirectory) ) .get() } }
上传网关:
@MessagingGateway interface UploadGateway { @Gateway(requestChannel = "toSftpChannel") fun upload(file: File) }
单元测试代码:
@Test fun `upload ach batch files to sftp`() = runTest { val test = File("src/test/resources/foo.txt") log.debug("uploading file: $test, ${test.exists()}") uploadGateway.upload(test) eventually(5.seconds) { Paths.get("./data/sftptest/foo.txt").shouldExist() } }
测试时本地文件存在,但上传抛出异常,核心错误栈:
Error handling message for file [D:\myproject\build\resources\test\foo.txt -> foo.txt]; nested exception is org.springframework.messaging.MessagingException: Failed to write to '/home/demo/sftp/foo.txt' while uploading the file; nested exception is java.io.IOException: failed to write file ... Caused by: 2: No such file at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873) at com.jcraft.jsch.ChannelSftp._put(ChannelSftp.java:594)
已创建示例项目复现问题,执行docker compose up sftp启动SFTP服务器,运行对应测试类即可复现。
问题原因与解决方案
1. 检查SFTP用户权限配置
emberstack/sftp的sftp.json配置文件中,需确保demo用户拥有目标目录的读写权限,且根目录设置正确。示例配置:
{ "Users": [ { "Username": "demo", "Password": "demo", "HomeDirectory": "/home/demo", "SshKeys": [], "Permissions": [ "ReadWrite /home/demo/sftp" ] } ] }
未配置权限会导致用户无法写入目标目录。
2. 调整远程目录配置
若remoteDirectory配置为绝对路径/home/demo/sftp,部分SFTP服务器会因用户根目录限制拒绝访问。建议改为相对路径sftp(相对于用户根目录/home/demo):
.remoteDirectory("sftp")
此时实际上传路径为/home/demo/sftp,与容器挂载目录匹配。
3. 验证容器内目录权限
进入容器检查/home/demo/sftp目录的所有者是否为demo用户:
docker exec -it <sftp容器ID> bash ls -l /home/demo/
若所有者不符,可在Docker Compose中指定用户UID/GID(需与容器内demo用户一致):
sftp: image: emberstack/sftp volumes: - ./data/sftp.json:/app/config/sftp.json:ro - ./data/sftptest:/home/demo/sftp:rw ports: - "2222:22" user: "1000:1000" # 替换为容器内demo用户的UID/GID
4. 启用远程目录自动创建
若目标目录可能不存在,在SFTP outbound adapter中添加自动创建目录配置:
Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL) .useTemporaryFileName(false) .remoteDirectory("sftp") .autoCreateDirectory(true) // 自动创建远程目录
内容的提问来源于stack exchange,提问作者Hantsy
相关产品推荐
相关产品推荐

