返回 导航

SpringBoot / Cloud

hangge.com

SpringBoot - 网络请求模版类RestTemplate使用详解7(异常处理、请求失败处理)

作者:hangge | 2019-11-01 08:19
    当我们使用 RestTemplate 发送请求时, 如果接口返回的不是 200 状态(而是 4xx5xx 这样的异常状态),则会抛出异常报错。
    
    但在实际接口对接中,我们可能希望获取接口返回的异常信息并返回(比如返回到前端)。这个可以通过自定义 RestTemplate 异常的处理来实现,下面通过样例进行演示。

十、请求异常处理

1,简单的样例代码

(1)首先我们需要创建一个自己的异常处理控制器(ExceptionHandler 类),该类实现 ResponseErrorHandler 接口。
public class RestThrowErrorHandler implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        // 返回false表示不管response的status是多少都返回没有错
        // 这里可以自己定义那些status code你认为是可以抛Error
        return false;
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        // 这里面可以实现你自己遇到了Error进行合理的处理
    }
}

(2)接着在 RestTemplate 配置类中,指定使用我们前面自定义的异常处理控制。
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory){
        RestTemplate restTemplate = new RestTemplate(factory);
        //Response status code 4XX or 5XX to the client.
        restTemplate.setErrorHandler(new RestThrowErrorHandler());
        return restTemplate;
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(15000); // 连接超时
        factory.setReadTimeout(5000); // 数据读取超时时间
        return factory;
    }
}

(3)最后是一个简单的请求样例。经过上面设置后,无论请求成功或者失败都会返回(不会抛异常),所以我们需要通过状态码来判断请求是否成功。
@RestController
public class HelloController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/test")
    public String test() {
        String url = "http://localhost:8080/xxxxxx";
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        // 判断请求是否发生异常
        if(!responseEntity.getStatusCode().is2xxSuccessful()){
            // 返回异常信息
            return "请求失败,异常信息:" + responseEntity.getBody();
        }
        // 没有异常的话则返回正常的响应结果
        return responseEntity.getBody();
    }
}

(4)由于代码中我们请求了一个不存在的接口,并且在请求失败时将错误信息返回到前端,因此前端会显示如下内容:

2,代码改进

(1)通常来说我们不会直接把业务代码写在 Controller 里,而是通过 Service 实现。首先我们创建一个 Service,里面调用 RestTemplate 进行网络请求,当请求异常时直接抛出异常。
@Service
public class UserService {

    @Autowired
    private RestTemplate restTemplate;

    public String getInfo() {
        String url = "http://localhost:8080/xxxxxx";
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        // 判断请求是否发生异常
        if(!responseEntity.getStatusCode().is2xxSuccessful()){
            // 抛出异常
            throw new RestClientException(responseEntity.getBody());
        }
        // 没有异常的话则返回正常的响应结果
        return responseEntity.getBody();
    }
}

(2)Controller 这边很简单,就是调用 Service 发起请求,然后返回结果。
@RestController
public class HelloController {

    @Autowired
    private UserService userService;

    @GetMapping("/test")
    public String test() {
        return userService.getInfo();
    }
}

(3)由于前面 Service 中我们将异常抛出了,所以要定义一个全局的异常处理类,捕获这个异常,并返回给前端处理的结果。
关于全局异常处理更详细用法可以参考我之前写的文章:
@ControllerAdvice
public class CustomExceptionHandler {
    @ExceptionHandler(RestClientException.class)
    public ResponseEntity<String> throwRestException(RestClientException restClientException){
        return new ResponseEntity<String>(restClientException.getMessage(),
                HttpStatus.BAD_REQUEST);
    }
}

(4)测试一下,可以看到异常信息已经返回到前端页面。
评论

全部评论(0)

回到顶部