serverless-java-container
serverless-java-container copied to clipboard
Unable to parse the content-type value from ALB request (json format)
- Framework version: 1.4
- Implementations: Spring Boot 2
Scenario
Using SAM cli pass the alb request sam local invoke -e alb-post.json
Here is the alb-post.json:
{ "requestContext": { "elb": { "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-279XGJDqGZ5rsrHC2Fjr/49e9d65c45c6791a" } }, "httpMethod": "POST", "path": "/accounts", "queryStringParameters": {}, "headers": { "accept": "application/json;v=1", "content-type": "application/json;v=1", "accept-encoding": "gzip", "accept-language": "en-US,en;q=0.9", "connection": "keep-alive", "host": "lambda-alb-123578498.us-east-2.elb.amazonaws.com", "upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", "x-amzn-trace-id": "Root=1-5c536348-3d683b8b04734faae651f476", "x-forwarded-for": "72.12.164.125", "x-forwarded-port": "11400", "x-forwarded-proto": "http", "x-imforwards": "20" }, "body": "{\"accountId\":\"9999\",\"nextScoreRefreshDate\":\"2018-12-06\"}", "isBase64Encoded": false }
Expected behavior
The rest controller should be invoke and insert the new account to database
Actual behavior
Get this error:
Unexpected and uncaught exceporg.springframework.web.HttpMediaTypeNotSupportedException: Content type '' not supported
Steps to reproduce
Run a sample pet-store with the ALB json request
Full log output
[2020-01-11 05:06:29.149] 982b37fe-a426-1403-10cf-41495a1288ec ERROR c.c.c.l.ScenarioReporter - CWCCD-2008, Description:Unexpected and uncaught exceporg.springframework.web.HttpMediaTypeNotSupportedException: Content type '' not supportedr at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:215)r at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:420)r at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:366)r at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:66)r at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:402)r at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1233)r at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1016)r at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)r at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)r at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)r at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)r at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)r at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainManager$ServletExecutionFilter.doFilter(FilterChainManager.java:351)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at com.filter.RequestLoggingFilter.doFilter(RequestLoggingFilter.java:49)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at com.filter.VersionFilter.doFilter(VersionFilter.java:49)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)r at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)r at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)r at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)r at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)r at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114)r at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.doFilter(AwsLambdaServletContainerHandler.java:150)r at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:143)r at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:43)r at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:211)r at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:246)r at com.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:34)r at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)r at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)r at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)r at java.lang.reflect.Method.invoke(Method.java:498)r at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:354)r at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:906)r at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:341)r at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:63)r at java.lang.Class.forName0(Native Method)r at java.lang.Class.forName(Class.java:348)r at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)r [2020-01-11 05:06:29.149] 982b37fe-a426-1403-10cf-41495a1288ec ERROR c.c.c.l.ScenarioReporter - CWCCD-2008, Description:Unexpected and uncaught exceporg.springframework.web.HttpMediaTypeNotSupportedException: Content type '' not supportedr at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:215)r at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:420)r at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:366)r at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:66)r at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:402)r at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1233)r at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1016)r at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)r at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)r at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)r at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)r at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)r at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainManager$ServletExecutionFilter.doFilter(FilterChainManager.java:351)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at com.filter.RequestLoggingFilter.doFilter(RequestLoggingFilter.java:49)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at com.filter.VersionFilter.doFilter(VersionFilter.java:49)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)r at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)r at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)r at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)r at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)r at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)r at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114)r at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)r at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)r at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:90)r at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.doFilter(AwsLambdaServletContainerHandler.java:150)r at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:143)r at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:43)r at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:211)r at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:246)r at com.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:34)r at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)r at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)r at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)r at java.lang.reflect.Method.invoke(Method.java:498)r at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:354)r at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:906)r at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:341)r at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:63)r at java.lang.Class.forName0(Native Method)r at java.lang.Class.forName(Class.java:348)r at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)r
It sounds like currently only header settings in MultiValueHeaders are extracted from the json request: https://github.com/awslabs/aws-serverless-java-container/blob/21430d65062f5f072a376f1d6e89ed7158b59ae8/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java#L377
With ALB, the header values could be in both headers or multiValueHeaders.
@dotekien the multiValueHeaders
map should always be populated, even if both properties are included. Is that not the case?
I'm sorry @dotekien - it is not by default, you need to configure ALB to populate those values. See the blog post here. We will update the documentation to clarify this and leave this issue open to collect feedback
This just bit me and cost me an hour or two of debugging. Not the end of the world, but it would be nice to add a blurb on the TargetGroup docs to this effect, at the very least. Perhaps right after:
Before you register a Lambda function as a target, you must create a AWS::Lambda::Permission resource that grants the Elastic Load Balancing service principal permission to invoke the Lambda function.
Would the team entertain a PR on those docs?
Or, alternatively, a code PR to this project that falls back to the single-value headers if the multi-value headers are not populated?
Or both?
Thanks for the feedback. We should definitely improve the docs.
The fallback also sounds good to me, can't think of any side-effects right now.
From above: I've proposed the code change in https://github.com/awslabs/aws-serverless-java-container/pull/470 and the documentation change in https://github.com/awsdocs/aws-cloudformation-user-guide/pull/1247.
Just checking in. Any thoughts, @deki?
Sorry for the delay @sigpwned, I was on vacation and had to catch up with a lot of things afterwards. I've commented in #470.
No problem at all, @deki. I understand busy, and I hope you enjoyed the vacation. I've responded over on #470!