最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Spring Boot web application returns HTTP 502 when deployed to AWS Lambda, but returns HTTP 500 in local deployment - Stac

programmeradmin7浏览0评论

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.

  1. 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.
  2. I invoked the same route /api/test/error with the app running in AWS Lambda (running with the SpringBootLambdaContainerHandler), 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.

  1. 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.
  2. I invoked the same route /api/test/error with the app running in AWS Lambda (running with the SpringBootLambdaContainerHandler), 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
Add a comment  | 

1 Answer 1

Reset to default 0

It 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.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论