SpringBoot部署AWS Lambda遇HttpMediaTypeNotSupportedException错误求助
在AWS Lambda中运行Spring Boot REST应用时,调用函数处理器(无论是RequestHandler<AwsProxyRequest, AwsProxyResponse>还是RequestStreamHandler),在handler.proxy或handler.proxyStream环节持续返回415错误:
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/octet-stream' is not supported] c.a.s.p.internal.LambdaContainerHandler : 127.0.0.1 null- null [11/10/2023:13:05:54Z] "POST /data/firstDataCreatedViaSpringBoot null" 415 - "-" "Custom User Agent String" combined
Spring Boot应用本地运行正常,但通过Lambda处理器接收请求时始终触发媒体类型不支持错误。已尝试在测试事件中添加Content-Type: application/json,并在Controller中添加consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,甚至通过Lambda函数URL直接调用(未经过API网关),问题依然存在。
1. 匹配Lambda调用方式选择对应处理器
SpringBootLambdaContainerHandler.getAwsProxyHandler()是为API Gateway代理请求设计的,它期望输入是AwsProxyRequest格式(包含headers、body等嵌套结构)。但直接使用Lambda函数URL调用时,请求输入是原始JSON体,而非AwsProxyRequest包装结构,这会导致Spring无法识别正确的Content-Type,默认被当作application/octet-stream。
此时应改用getRawHandler()处理原始请求:
public class LambdaHandler implements RequestStreamHandler { private static SpringBootLambdaContainerHandler<InputStream, OutputStream> handler; static { try { // 使用RawHandler处理原始请求,而非Api Gateway的Proxy格式 handler = SpringBootLambdaContainerHandler.getRawHandler(DataDemoApplication.class); } catch (ContainerInitializationException e) { throw new RuntimeException("Could not initialize Spring Boot application", e); } } @Override public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { handler.proxyStream(inputStream, outputStream, context); } }
2. 修正Controller的媒体类型配置
移除仅支持application/octet-stream的配置,恢复或添加对application/json的支持,兼容两种请求场景:
@RestController @RequestMapping(value = "/data", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE}) public class DataController { // ... 你的接口实现 }
3. 调整Lambda控制台测试事件格式
如果使用Lambda控制台测试函数URL调用,不需要使用AwsProxyRequest格式,直接发送原始JSON体即可:
{"name": "Jarda", "email": "jarda@idc.com"}
同时在测试配置的"Headers"中添加Content-Type: application/json。
4. 手动包装请求(可选)
如果必须使用AwsProxyRequest处理器且直接调用Lambda函数URL,可在处理器中手动将原始请求包装为AwsProxyRequest并设置正确的Content-Type:
@Override public AwsProxyResponse handleRequest(InputStream inputStream, Context context) throws IOException { // 读取原始请求体 String body = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); // 构造AwsProxyRequest,设置正确的Content-Type AwsProxyRequest request = new AwsProxyRequest(); request.setHttpMethod("POST"); request.setPath("/data/firstDataCreatedViaSpringBoot"); request.setBody(body); Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); request.setHeaders(headers); return handler.proxy(request, context); }
内容的提问来源于stack exchange,提问作者Radek

