使用Apache Camel进行SFTP文件传输失败的排查求助
SFTP文件抓取-归档-解密逻辑异常排查方案
问题背景
本地目录测试时,文件抓取→归档→解密的逻辑完全正常,但切换到SFTP环境后无法执行成功。已确认SFTP连接正常:不传私钥会触发连接异常,传私钥后路由无报错,但无任何文件复制动作。使用的是SFTP端的绝对目录。
排查方案与下一步操作建议
修正路由语法错误
你的路由代码中,.to(sfpArchive);后面的分号直接截断了后续的解密和输出步骤,这是核心问题!
错误代码片段:from(sftpInput) .to(sfpArchive); // 分号导致后续步骤未加入路由链 .unmarshal(pgpDataFormat) .to(sfpOutput);正确写法(去掉分号,保持链式调用):
from(sftpInput) .to(sfpArchive) .unmarshal(pgpDataFormat) .to(sfpOutput);验证SFTP URI正确性
- 打印
buildURISFTP生成的sftpInput、sfpArchive、sfpOutput三个完整URI,检查绝对目录是否以/开头(如/remote/input),避免路径拼接错误。 - 用SFTP客户端(如FileZilla)使用相同账号、私钥访问生成的URI路径,确认路径存在且可读写。
- 打印
检查SFTP权限
- 确认SFTP用户对输入目录有读取权限,归档/输出目录有写入权限,权限不足常导致无操作但无报错。
- 手动用该账号在对应目录执行上传、下载、移动文件操作,验证权限正常。
开启DEBUG日志排查
在SFTP URI的options中添加&loggingLevel=DEBUG,查看Camel与SFTP交互的详细日志,确认是否扫描到文件、是否有隐藏异常。调整Camel SFTP配置参数
- 添加
&consumer.delay=1000缩短扫描间隔,避免因默认间隔过长导致超时前未执行操作。 - 添加
&maxMessagesPerPoll=1限制单次扫描处理的文件数量,先测试单个文件的完整流程。 - 确认URI中添加了
&binary=true,保证文件以二进制模式传输,避免PGP文件损坏。
- 添加
检查超时时间设置
确认Thread.sleep(timeout)中的timeout值足够长,至少大于SFTP扫描间隔+文件处理时间,避免Camel上下文提前停止。验证PGP解密环境
- 确认
pPgpSecretKey指向的密钥文件在部署环境中存在且有读取权限。 - 对比SFTP归档后的文件与本地测试文件的MD5值,确认文件未在传输中损坏。
- 确认
相关代码
主逻辑代码
CamelContext camelContext = new DefaultCamelContext(); camelContext.getRegistry().bind("SFTPPrivateKey",Byte[].class,privateKey.getBytes()); String sftpInput = buildURISFTP(input,inputOptions,connectionConfig); String sfpOutput = buildURISFTP(output,outputOptions,connectionConfig); String sfpArchive = buildURISFTP(archive,archiveOptions,connectionConfig); camelContext.addRoutes(new RouteBuilder() { public void configure() throws Exception { PGPDataFormat pgpDataFormat = new PGPDataFormat(); pgpDataFormat.setKeyFileName(pPgpSecretKey); pgpDataFormat.setKeyUserid(pgpUserId); pgpDataFormat.setPassword(pgpPassword); pgpDataFormat.setArmored(true); from(sftpInput) .to(sftpArchive); //tested decryption local with file to file routing .unmarshal(pgpDataFormat) .to(sfpOutput); } }); camelContext.start(); Thread.sleep(timeout); camelContext.stop();
SFTP URI构建代码
public String buildURISFTP(String directory, String options, ConnectionConfig connectionConfig){ StringBuilder uri = new StringBuilder(); uri.append("sftp://"); uri.append(connectionConfig.getSftpHost()); uri.append(":"); uri.append(connectionConfig.getSftpPort()); uri.append(directory); uri.append("?username="); uri.append(connectionConfig.getSftpUser()); if(!StringUtils.isEmpty(connectionConfig.getSftpPassword())){ uri.append("&password="); uri.append(connectionConfig.getSftpPassword()); } uri.append("&privateKey=#SFTPPrivateKey"); if(!StringUtils.isEmpty(options)){ uri.append(options); } return uri.toString(); }
内容的提问来源于stack exchange,提问作者Zach
相关产品推荐
相关产品推荐

