Open deki opened 2 years ago
In AwsProxyHttpServletRequestReader
The condition fails because when a request from a function url is mapped to a AwsProxyRequest
type getHttpMethod()
returns null.
HttpApiV2ProxyHandler along with HttpApiV2ProxyRequest needs to be used, than it works fine. Will change docs and samples.
If I use the example request from the developer guide
{
// removed for brevity
"requestContext": {
"accountId": "123456789012",
"apiId": "<urlid>",
"authentication": null,
"authorizer": {
"iam": {
"accessKey": "AKIA...",
"accountId": "111122223333",
"callerId": "AIDA...",
"cognitoIdentity": null,
"principalOrgId": null,
"userArn": "arn:aws:iam::111122223333:user/example-user",
"userId": "AIDA..."
}
},
"domainName": "<url-id>.lambda-url.us-west-2.on.aws",
"domainPrefix": "<url-id>",
"http": {
"method": "POST",
"path": "/my/path",
"protocol": "HTTP/1.1",
"sourceIp": "123.123.123.123",
"userAgent": "agent"
},
// removed for brevity
}
Then I get the following error and a 502 http response.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "authentication" (class com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequestContext), not marked as ignorable (11 known properties: "apiId", "domainPrefix", "accountId", "authorizer", "requestId", "timeEpoch", "time", "stage", "domainName", "routeKey", "http"])
at [Source: (ByteArrayInputStream); line: 21, column: 27] (through reference chain: com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest["requestContext"]->com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequestContext["authentication"])
This is because HttpApiV2ProxyRequestContext
is not ignoring fields that it doesn't recognise, in this case authentication
.
To fix this we could add @JsonIgnoreProperties(ignoreUnknown = true)
to the class so that Jackson ignores fields it doesn't recognise.
The fix mentioned above works for me. Thx!
public class StreamLambdaHandler implements RequestStreamHandler {
// private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
private static SpringBootLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> handler;
static {
try {
// handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
handler = SpringBootLambdaContainerHandler.getHttpApiV2ProxyHandler(Application.class);
Hey guys, thanks for this change. But is it possible to have ONE handler for all types of events? ALB, API_GW, functional url and so on? So far I see the ways how handlers are initialized are way different and it seems that I have to keep 2X resources in lambda to keep 2 types of handlers in memory - one for ALB, API_GW and another for FURL. Is there a way to share a single handler for all types of events?
@astsiatsko which framework are you using?
For Spring Boot 3 you have the possibility to use the new SpringDelegatingLambdaContainerHandler
as described in https://github.com/aws/serverless-java-container/tree/main/samples/springboot3/alt-pet-store. This one supports both payload versions. More docs on this coming soon...
@deki thanks! I am using spring boot 3.1.x. Thank you, I will give it a try and let you know asap.
@deki One question - may I do sth like that?
SpringDelegatingLambdaContainerHandler.getContainerConfig().setInitializationTimeout(timeout);
This is currently not implemented for this handler type. Please open a new issue describing your requirement and someone will look into it.
Hey guys. Sorry for asking but are you sure your approach works for complex urls with query and path parameters? I use SpringDelegatingLambdaContainerHandler in complex enterprise lambda function and on
mvc.service(httpServletRequest, httpServletResponse);
I constantly get error 400 and /error context path. I copied SpringDelegatingLambdaContainerHandler to the same package in my app and added logs. In my query I have two query params and path param. In aws logs I see it starts spring boot but I always get 400 and /error in logs instead of my url. I use ALB event, but it doesn't work for others either. Can you help please?
My endpoint signature:
@RequestMapping(path = "/w6/test/{uuid}/refresh", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<TMaxmindResponse> refresh(
@Parameter(description = "UUID of the order") @PathVariable("uuid") String uuid,
@Parameter(description = "ID of the order(primary key)") @RequestParam("order_id") Long orderId,
@Parameter(description = "tab") @RequestParam("tab") String tab
)
Hey guys. I think you have a problem with query parameters procession - I changed all my parameters to path params and it worked just fine. I debugged it in AWS Lambda for 2 days and gave it up, decided to move to path variables. But please, fix that or let me know what I am doing wrong. Thanks
Here is the stack trace I have. May be it helps
jakarta.servlet.ServletException: Request processing failed: java.lang.NullPointerException: Cannot read the array length because \"\u003cparameter1\u003e\" is null\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1019)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc$ProxyFilterChain$ServletFilterProxy.doFilter(ProxyMvc.java:280)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc$ProxyFilterChain.doFilter(ProxyMvc.java:233)\n\tat org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:289)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc$ProxyFilterChain.doFilter(ProxyMvc.java:233)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc$ProxyFilterChain.doFilter(ProxyMvc.java:233)\n\tat org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc$ProxyFilterChain.doFilter(ProxyMvc.java:233)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc.service(ProxyMvc.java:144)\n\tat org.springframework.cloud.function.serverless.web.ProxyMvc.service(ProxyMvc.java:138)\n\tat com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler.handleRequest(SpringDelegatingLambdaContainerHandler.java:74)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)\n\tat java.base/java.lang.reflect.Method.invoke(Unknown Source)\n\tat com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:378)\n\tat com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$2.call(EventHandlerLoader.java:905)\n\tat com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:245)\n\tat com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:197)\n\tat com.amazonaws.services.lambda.runtime.api.client.AWSLambda.main(AWSLambda.java:187)\nCaused by: java.lang.NullPointerException: Cannot read the array length because \"\u003cparameter1\u003e\" is null\n\tat java.base/java.io.ByteArrayInputStream.\u003cinit\u003e(Unknown Source)\n\tat org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest.getInputStream(ProxyHttpServletRequest.java:280)\n\tat org.springframework.web.util.ContentCachingRequestWrapper.getInputStream(ContentCachingRequestWrapper.java:98)\n\tat org.springframework.http.server.ServletServerHttpRequest.getBody(ServletServerHttpRequest.java:206)\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver$EmptyBodyCheckingHttpInputMessage.\u003cinit\u003e(AbstractMessageConverterMethodArgumentResolver.java:323)\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:172)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:163)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:136)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:181)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:148)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)\n\t... 27 more\n","timestamp":"2024-01-26 18:07:19.251"}
@astsiatsko good catch, would you mind opening a new issue for it? This is unrelated to Lambda Function URLs. We'll include a fix in the next release.
@deki Thank you I submitted https://github.com/aws/serverless-java-container/issues/754
@deki you can assign it to me
Recently Lambda Function URLs were released: https://aws.amazon.com/blogs/aws/announcing-aws-lambda-function-urls-built-in-https-endpoints-for-single-function-microservices/
Those requests fail with:
com.amazonaws.serverless.exceptions.InvalidRequestEventException: The incoming event is not a valid request from Amazon API Gateway or an Application Load Balancer