Spring Boot FTP功能本地正常,Docker部署后异常求助
Spring Boot FTP接口Docker部署异常排查
本地环境调用外部FTP服务正常,部署到Debian VPS的Docker容器后出现以下问题:
/api/getfile接口返回200状态码但无数据返回/api/uploadfile接口返回false
控制器代码(FileController.java)
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; import java.util.List; @CrossOrigin @RestController public class FileController { FtpUtil ftpUtil; @Scheduled(fixedDelay = 5000) @PostMapping("/api/uploadfile") public boolean uploadFile(@RequestParam(value ="file") MultipartFile file) throws IOException { InputStream inputStream = file.getInputStream(); return ftpUtil.uploadFile("ftp.host.fr",21,"user","password","./assets/images/jej", "/",file.getOriginalFilename(), inputStream); } @Scheduled(fixedDelay = 5000) @GetMapping("/api/getfile") public List<String> getFileList() { return ftpUtil.udownLoadFile("host",21,"user","pass","./assets/images/jej"); } }
FTP工具类代码(FtpUtil.java)
import java.io.*; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; public class FtpUtil { public static boolean uploadFile(String host, int port, String username, String password, String basePath, String filePath, String filename, InputStream input) { FTPClient ftp = new FTPClient(); Boolean result = false; try { ftp.connect(host, port); ftp.login(username, password); int reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return result; } String path = basePath + filePath; if (!ftp.changeWorkingDirectory(path)) { String[] dirs = path.split("/"); StringBuffer tempPath = new StringBuffer(); for (String dir : dirs) { if (null == dir || "".equals(dir)) { continue; } tempPath.append("/").append(dir); if (!ftp.changeWorkingDirectory(tempPath.toString())) { if (!ftp.makeDirectory(tempPath.toString())) { return result; } else { ftp.changeWorkingDirectory(tempPath.toString()); } } } } ftp.setFileType(FTPClient.BINARY_FILE_TYPE); if (!ftp.storeFile(filename, input)) { return result; } input.close(); ftp.logout(); result = true; } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return result; } public static List<String> udownLoadFile(String host, int port, String username, String password, String remotePath) { FTPClient ftp = new FTPClient(); try { int reply; ftp.connect(host, port); ftp.login(username, password); reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); } ftp.changeWorkingDirectory(remotePath); FTPFile[] fs = ftp.listFiles(); return Arrays.stream(fs) .map(FTPFile::getName) .collect(Collectors.toList()); } catch (Exception e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return null; } }
Docker运行命令
docker container run --network jejnet --name je2 -p 8080:8080 -v slaateejej-volume -d slaatee/jej:trya
排查方向与解决步骤
1. 网络连通性验证
Docker容器默认使用桥接网络,需确认容器能正常访问外部FTP服务器:
- 进入容器执行
ping ftp.host.fr,检查DNS解析与网络连通性 - 执行
telnet ftp.host.fr 21,验证FTP端口是否可访问 - 若使用自定义网络
jejnet,确认该网络的防火墙规则允许出站访问21端口
2. 配置FTP被动模式
多数FTP服务器默认使用被动模式,容器内未配置会导致数据传输失败:
- 在
FtpUtil的ftp.login()后添加被动模式配置:ftp.enterLocalPassiveMode(); - 若FTP服务器指定了被动端口范围,需在Docker运行命令中映射对应端口(如
-p 21000-21010:21000-21010),并在VPS防火墙开放这些端口
3. 修正文件路径问题
代码中使用相对路径./assets/images/jej,容器内工作目录可能与本地不一致:
- 改为FTP服务器的绝对路径(如
/assets/images/jej) - 或在
ftp.changeWorkingDirectory前打印当前工作目录,确认路径有效性
4. 完善异常日志
目前仅控制台打印异常,容器日志可能未捕获关键错误:
- 使用SLF4J等日志框架将异常信息写入日志文件
- 执行
docker logs je2查看容器运行日志,定位具体错误
5. 权限检查
- 确认FTP账号对目标目录有读写权限
- 检查容器内应用运行用户是否有足够权限操作上传输入流
内容的提问来源于stack exchange,提问作者Sylvain Le Bren
相关产品推荐
相关产品推荐

