首页 > 解决方案 > 如何使用 REST Web 服务和 Spring 中的 CompletableFuture 类捕获异常?

问题描述

我已经使用 spring 框架和 REST 开发了一些异步 Web 服务,我已经从使用 spring class 创建的客户端使用它AsyncRestTemplate。类返回一个对象ListenableFuture<ResponseEntity<T>>(使用方法getForEntity),它带来 Web 服务返回的值(使用方法.get():<T>)。它工作正常,但是当 REST Web 服务(扩展类)中发生自定义异常时,RuntimeException客户端无法正确捕获它,它会向我显示以下消息:

“时间戳”:“2018-05-28T14:25:15.393+0000”,“状态”:500,
“错误”:“内部服务器错误”,“消息”:“java.util.concurrent.ExecutionException:org.springframework .web.client.HttpServerErrorException: 500 null",
"path": "/client/result"

有人知道我该如何解决这个问题吗?我希望客户端向我显示自定义异常消息。

服务器代码如下:

配置类:

@Configuration
@EnableAsync
public class ConfigurationClass {
    @Bean
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}

控制器类:

@RestController
@RequestMapping("/server")
public class ControllerClass {

    @GetMapping("/start")
    @Async
    public CompletableFuture<String>  callService() throws InterruptedException{
        Thread.sleep(10000L);
        if(true)
            throw new RuntimeException("Custom Error");
        return CompletableFuture.completedFuture("OK");
    }
}

客户端代码(消费者)如下:

@RestController
@RequestMapping("/client")
public class ControllerClass {

    private ListenableFuture<ResponseEntity<String>> entity;

    @GetMapping("/start")
    @Async
    public void callService() throws InterruptedException {
        AsyncRestTemplate restTemplate = new AsyncRestTemplate();
        entity = restTemplate.getForEntity("http://localhost:8080/server/start",
                 String.class);
    }

    @GetMapping("/state")
    public boolean getState() {
        try {
            return entity.isDone();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @GetMapping("/result")
    public ResponseEntity<String> getResult() {
        try {
            return entity.get();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

感谢您的帮助,问候。

已于 2018 年 5 月 19 日添加---------------------------------------

我接近解决方案。在 web 服务的控件类中,我添加了用 注释的方法@ExceptionHandler,如下代码所示:

@ExceptionHandler(RuntimeException.class)
    void handleIllegalArgumentException(HttpServletResponse response) throws IOException {
        response.sendError(200, "custom Error");
    }

它工作正常,客户端已经正确识别异常,但是,如果我在 web 服务中通过其他更改状态(如 201、400、401,它们是HTTP 有效状态),我会返回获取消息"java.util.concurrent.ExecutionException: org.springframework.web.client.HttpServerErrorException: 500 null",在客户端。

有人知道原因吗?

标签: javaspringrestasynchronous

解决方案


RestTemplate收到 4xx 或 5xx 响应码时,它认为这是一个错误并抛出一个HttpClientErrorException/ HttpServerErrorException,而不是返回一个ResponseEntity

对于您的用例,您可以设置一个错误处理程序(从 扩展DefaultResponseErrorHandler),它不会将 4xx 和 5xx 响应视为错误。

代替

AsyncRestTemplate restTemplate = new AsyncRestTemplate();

使用以下代码

    AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
    asyncRestTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
        @Override
        protected boolean hasError(HttpStatus statusCode) {
            return false;
        }
    });

推荐阅读