Spring集成AmazonS3客户端上传文件时出现序列化错误的咨询
问题根因
你的推测基本正确,触发序列化错误的核心原因是:AmazonS3Client类没有实现Serializable接口,当S3上传抛出异常时,异常链路中持有AmazonS3Client的实例引用,而Spring Session在序列化会话数据(包括SecurityContext、会话属性、甚至被捎带存入会话的异常对象)时,默认使用JDK序列化,要求所有序列化链路中的对象都必须实现Serializable接口,因此触发报错。
你直接抛自定义异常时没有关联S3相关的原始异常,所以不会触发序列化问题,也符合这个根因特征。
可落地的解决方案
- 方案1:截断异常链路中的S3相关引用(最简单,推荐)
不要把S3抛出的原始异常作为自定义异常的cause传入,先在catch块打印完整异常日志方便排查,再抛出仅携带错误提示消息的自定义异常即可,修改manualUpload的catch块逻辑:
如果你需要避免文件重名覆盖,也可以自行生成唯一的存储键替换原文件名。try { // 这里同时修复原代码逻辑bug:原代码用file.getName()取的是表单字段名,改为getOriginalFilename()才能拿到用户上传的原文件名 amazonS3.putObject(new PutObjectRequest(bucketName, file.getOriginalFilename(), file.getInputStream(), metadata)); } catch (Exception e) { // 先打印完整异常栈到日志,不丢失排查信息 log.error("S3文件上传失败,桶名:{},文件名:{}", bucketName, file.getOriginalFilename(), e); // 抛出自定义异常,仅传入提示消息,不携带原始异常对象 throw new UploadException("文件上传失败:" + e.getMessage()); } - 方案2:替换Spring Session序列化器(适用需要保留完整异常链路的场景)
把Spring Session默认的JDK序列化替换为Jackson2JSON序列化,不需要对象实现Serializable接口也能完成序列化,直接注册对应Bean即可:import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.session.serializer.Jackson2JsonSpringSessionSerializer; import org.springframework.session.serializer.SpringSessionSerializer; @Configuration public class SpringSessionConfig { @Bean public SpringSessionSerializer<Object> springSessionSerializer() { return new Jackson2JsonSpringSessionSerializer(); } } - 方案3:标记不可序列化字段跳过序列化
如果你将会话作用域的Bean注入了AmazonS3Client,直接给该字段加上transient修饰符,序列化时会自动忽略该字段:@Component @SessionScope public class YourSessionScopedBean { // 加transient跳过JDK序列化 private transient final AmazonS3 amazonS3; public YourSessionScopedBean(AmazonS3 amazonS3) { this.amazonS3 = amazonS3; } }
内容的提问来源于stack exchange,提问作者Rafał Sokalski
相关产品推荐
相关产品推荐

