如何使用Lambda + Java从S3收集文件并发送至外部SFTP?
我来给你一步步拆解这个需求,帮你理清思路并给出可落地的Java实现示例:
Java Lambda实现S3文件转发至SFTP的完整指南
核心疑问先给你捋清楚
- Lambda与S3的连接方式:完全不用像外部环境那样手动建立HTTP连接或者配置复杂的客户端!AWS提供的Java SDK(
aws-sdk-java-v2)已经做了完整封装,Lambda运行时会自动获取IAM角色的权限,直接调用S3 API就能操作文件。而且最佳实践是通过S3事件通知触发Lambda——当有新文件存入桶时,S3会自动把事件推送给Lambda,不用你写代码主动轮询S3,效率高还省资源。 - 是否需要调用其他Lambda:如果你的业务逻辑特别复杂(比如把文件编辑和转发拆成独立步骤),可以拆分多个Lambda互相调用,但对于简单的“获取S3文件→编辑→转发SFTP”流程,单Lambda就能搞定,没必要额外拆分增加复杂度。
实现步骤与代码示例
1. 前期准备工作
- 给Lambda配置专用IAM角色,必须包含这些权限:
- S3读取权限(
s3:GetObject),用来获取文件 - 可选:S3修改/删除权限(如果需要重命名源文件或处理后删除)
- Secrets Manager权限(如果把SFTP的账号密码存在这里,绝对不要硬编码!)
- S3读取权限(
- 打包依赖:Lambda运行时默认没有SFTP客户端库,需要把
com.jcraft:jsch(常用的Java SFTP库)和AWS SDK一起打包,或者用Lambda Layer来管理依赖,减少包体积。
2. Lambda核心代码实现
下面是一个简化版的完整逻辑,包含S3文件读取、重命名、SFTP上传的全部流程:
import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.S3Object; import com.jcraft.jsch.*; import java.io.*; import java.util.Properties; public class S3ToSftpLambdaHandler implements RequestHandler<S3Event, Void> { // 初始化S3客户端(Lambda运行时自动处理权限认证,不用手动配置) private final S3Client s3Client = S3Client.builder().region(Region.US_EAST_1).build(); // SFTP配置:生产环境建议从Secrets Manager读取,这里简化为常量示例 private static final String SFTP_HOST = "你的SFTP服务器地址"; private static final int SFTP_PORT = 22; private static final String SFTP_USER = "SFTP用户名"; private static final String SFTP_PASSWORD = "SFTP密码"; private static final String SFTP_TARGET_DIR = "/远程SFTP目标目录/"; @Override public Void handleRequest(S3Event s3Event, Context context) { // 遍历S3事件中的所有新文件记录 for (S3EventNotificationRecord record : s3Event.getRecords()) { String bucketName = record.getS3().getBucket().getName(); String objectKey = record.getS3().getObject().getKey(); try { // 1. 从S3获取文件流 S3Object s3Object = s3Client.getObject(GetObjectRequest.builder() .bucket(bucketName) .key(objectKey) .build()); InputStream fileInputStream = s3Object.content(); // 2. 重命名示例:给原文件名加上时间戳前缀,避免重复 String newFileName = System.currentTimeMillis() + "_" + objectKey; // 3. 上传处理后的文件到SFTP服务器 uploadToSftp(fileInputStream, newFileName); // 可选操作:如果需要处理完删除S3源文件,打开下面的注释 // s3Client.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(objectKey).build()); } catch (Exception e) { context.getLogger().log("处理文件失败: " + objectKey + ", 错误信息: " + e.getMessage()); throw new RuntimeException("文件处理流程失败", e); } } return null; } // SFTP上传工具方法 private void uploadToSftp(InputStream inputStream, String fileName) throws JSchException, IOException { JSch jsch = new JSch(); Session session = jsch.getSession(SFTP_USER, SFTP_HOST, SFTP_PORT); session.setPassword(SFTP_PASSWORD); // 配置SFTP会话:生产环境建议配置信任的主机密钥,这里暂时跳过检查 Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); // 建立连接并上传文件 session.connect(); ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); channelSftp.cd(SFTP_TARGET_DIR); channelSftp.put(inputStream, fileName); // 关闭资源,避免内存泄漏 channelSftp.disconnect(); session.disconnect(); } }
3. 关键注意事项
- 依赖打包:用Maven或Gradle打包时,要把所有依赖(包括JSch和AWS SDK)打包成Fat Jar,或者把JSch放到Lambda Layer中,不然Lambda运行时会找不到类。
- 凭证安全:绝对不要把SFTP的账号密码硬编码在代码里,一定要存在AWS Secrets Manager中,在Lambda启动时通过SDK读取。
- 超时配置:如果文件较大,上传SFTP可能需要更长时间,记得在Lambda控制台把超时时间调整到足够长(比如5分钟),避免中途被强制终止。
- 错误重试:建议添加重试机制(比如用AWS Step Functions),如果SFTP上传失败,能自动重试,避免丢失文件。
内容的提问来源于stack exchange,提问作者Thai Rodrigues
相关产品推荐
相关产品推荐

