I intentionally coded my controller to throw an exception so I could test the application's failure modes, but I'm not getting consistent results between running locally and running within AWS.
- I invoked my route
/api/test/error
with the Spring Boot application locally (running with embedded Tomcat) and received HTTP 500 with the Spring Boot default error JSON object. - I invoked the same route
/api/test/error
with the app running in AWS Lambda (running with theSpringBootLambdaContainerHandler
), but received HTTP 502 with just a basic JSON object containing only a generic exception message (not the Spring Boot default error JSON object).
Why is this behaving differently?
(There is a somewhat similar question here, but based on the comments, the author was not dealing with exception handling).
Here is my Controller:
@RestController
public class TestController {
@GetMapping("/api/test/error")
public String error() {
throw new IllegalStateException("This is a test exception");
}
}
And my Lambda Request Handler:
public class LambdaRequestHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
private final static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = new SpringBootProxyHandlerBuilder<AwsProxyRequest>()
.defaultProxy()
.initializationWrapper(new InitializationWrapper())
.springBootApplication(MyApplication.class)
.servletApplication()
.buildAndInitialize();
} catch (ContainerInitializationException e) {
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
@Override
public AwsProxyResponse handleRequest(AwsProxyRequest input, Context context) {
return handler.proxy(input, context);
}
}
I intentionally coded my controller to throw an exception so I could test the application's failure modes, but I'm not getting consistent results between running locally and running within AWS.
- I invoked my route
/api/test/error
with the Spring Boot application locally (running with embedded Tomcat) and received HTTP 500 with the Spring Boot default error JSON object. - I invoked the same route
/api/test/error
with the app running in AWS Lambda (running with theSpringBootLambdaContainerHandler
), but received HTTP 502 with just a basic JSON object containing only a generic exception message (not the Spring Boot default error JSON object).
Why is this behaving differently?
(There is a somewhat similar question here, but based on the comments, the author was not dealing with exception handling).
Here is my Controller:
@RestController
public class TestController {
@GetMapping("/api/test/error")
public String error() {
throw new IllegalStateException("This is a test exception");
}
}
And my Lambda Request Handler:
public class LambdaRequestHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
private final static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = new SpringBootProxyHandlerBuilder<AwsProxyRequest>()
.defaultProxy()
.initializationWrapper(new InitializationWrapper())
.springBootApplication(MyApplication.class)
.servletApplication()
.buildAndInitialize();
} catch (ContainerInitializationException e) {
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
@Override
public AwsProxyResponse handleRequest(AwsProxyRequest input, Context context) {
return handler.proxy(input, context);
}
}
Share
Improve this question
asked Mar 10 at 21:41
Alessandro ScarlattiAlessandro Scarlatti
7348 silver badges21 bronze badges
1 Answer
Reset to default 0It turns out this is because Spring Boot itself does not actually produce the default error response and associated JSON object internally to DispatcherServlet
(which is what the SpringBootLambdaContainerHandler
is invoking).
Instead, the default error response and associated JSON object are created when the exception bubbles up out of DispatcherServlet
to be handled by Tomcat itself. Then, Tomcat adds the exception to the Request Context, and sends DispatcherServlet another request, this time for /error
(or whatever you have configured Spring to use as the "default error route").
On the SpringBootLambdaContainerHandler
side of things, the exception bubbles out of DispatcherServlet
into the SpringBootLambdaContainerHandler
and it uses its default ExceptionHandler
instance (which you can override) to handle the exception, and by default this exception handler returns an HTTP 502 response with most exception types.
Also note that this is an issue that will only arise for a Servlet web application. This is not an issue for a Spring Reactive web application. The default error response and JSON object are handled by Spring directly "within" the context of the original request with a Reactive web application.
If you wish to standardize the response from exceptions thrown in controller methods, either explicitly handle all exceptions in each controller method, or consider more generic exception handling with @ControllerAdvice
.