【问题标题】:How do I retrieve HTTP status code and response body when an RestClientException is thrown?抛出 RestClientException 时如何检索 HTTP 状态代码和响应正文?
【发布时间】:2012-09-15 05:40:15
【问题描述】:

RestTemplate 的方法如postForEntity() 抛出RestClientException。我想从 catch 块中的异常对象中提取 HTTP 状态代码和响应正文。我该怎么做?

【问题讨论】:

    标签: java resttemplate


    【解决方案1】:

    不要捕捉RestClientException,而是捕捉特殊的HttpClientErrorException

    这是一个例子:

    try {
        Link dataCenterLink = serviceInstance.getLink("dataCenter");
        String dataCenterUrl = dataCenterLink.getHref();
        DataCenterResource dataCenter =
            restTemplate.getForObject(dataCenterUrl, DataCenterResource.class);
        serviceInstance.setDataCenter(dataCenter);
    } catch (HttpClientErrorException e) {
        HttpStatus status = e.getStatusCode();
        if (status != HttpStatus.NOT_FOUND) { throw e; }
    }
    

    HttpClientErrorException 提供getStatusCodegetResponseBodyAsByteArray 分别获取状态码和正文。

    【讨论】:

    • 更通用的是HttpStatusCodeException,由HttpClientErrorExceptionHttpServerErrorException继承。
    • 如果你捕捉到HttpStatusCodeException,你就可以访问方法getResponseBodyAsString()
    • 这个答案我缺少什么?如果您正在调用返回 RestClientException 的方法,您不能只是神奇地将其转换为 HttpClientErrorException 对吗?
    【解决方案2】:

    在某些情况下,不会抛出 HttpClientErrorException。比如下面的方法restTemplate.exchange调用:

    ResponseEntity<Employee[]> employees =  restTemplate.exchange(url, HttpMethod.GET, entity, Employee[].class);
    

    获取 http 正文并将其编组到实体。如果远程资源返回一个罕见的错误,则内部编组不起作用,只会抛出 RestClientException

    restTemplate.setErrorHandler

    在这种情况下,或者如果您想处理 restTemplate 操作中的任何错误,您可以使用 setErrorHandler。这个方法接收一个基本的 ResponseErrorHandler 和有用的方法。

    这个方法hasError让我可以获取远程http正文并帮助我检测调用的错误或者远程http远程资源中的错误:

    restTemplate.setErrorHandler(new ResponseErrorHandler() {
    
      @Override
      public boolean hasError(ClientHttpResponse arg0) throws IOException {
    
        System.out.println("StatusCode from remote http resource:"+arg0.getStatusCode());
        System.out.println("RawStatusCode from remote http resource:"+arg0.getRawStatusCode());
        System.out.println("StatusText from remote http resource:"+arg0.getStatusText());
    
        String body = new BufferedReader(new InputStreamReader(arg0.getBody()))
              .lines().collect(Collectors.joining("\n"));
    
        System.out.println("Error body from remote http resource:"+body);
        return false;
      }
    
      @Override
      public void handleError(ClientHttpResponse arg0) throws IOException {
        // do something
      }
    });
    

    此外,您可以手动评估正文或状态并返回 true 或 false 以标记为错误与否。

    【讨论】:

      【解决方案3】:

      改为使用RestClientResponseException。它更通用。

      来自docs:包含实际 HTTP 响应数据的异常的通用基类。

      【讨论】:

      • 捕获该异常是可行的,但是,我更喜欢 HttpClientErrorException 因为您可以获得响应正文以及带有相应消息的完整 HttpStatus 对象/枚举。示例:您可以在使用另一个时获得“404”代码以及“未找到”描述。
      【解决方案4】:
      private void sendActivity(StatsActivity statsActivity) throws InterruptedException 
      {
          LibraryConnectorXapiEditView libraryConnectorXapiEditView = (LibraryConnectorXapiEditView) workerBundle.getConnector();
          
          RestTemplate restTemplate = new RestTemplate();
          restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
          Statement statement = libraryConnectorConverter.convertActivityToStatement(statsActivity, workerBundle);
          HttpEntity<Statement> request = new HttpEntity<>(statement, headers);
          
          try
          {
             String lrsEndPoint = libraryConnectorXapiEditView.getLrsEndPoint() + "/statements";
             ResponseEntity<String> response = restTemplate.exchange(lrsEndPoint, HttpMethod.POST, request, String.class);
             ocnCompletionEventDao.save(this.convertToOcnCompletionEvent(statsActivity, response.getBody(), response.getStatusCodeValue()));
          }
          catch (HttpClientErrorException ex)
          {
            ocnCompletionEventDao.save(this.convertToOcnCompletionEvent(statsActivity, ex.getResponseBodyAsString(), ex.getStatusCode().value()));
            checkResponse(ex, libraryConnectorXapiEditView);  
            if(failedAttempts<3) 
            { 
                sendActivity(statsActivity);
                failedAttempts++;
            }
          }   
      }
      
      private void checkResponse(HttpClientErrorException ex, LibraryConnectorXapiEditView libraryConnectorXapiEditView) throws InterruptedException 
      {
          int statusCode = ex.getStatusCode().value();
          int retryAfterSeconds = retryAfter(ex.getResponseHeaders());
          
          switch (statusCode)
          {
          case 401: 
              headers = xApiAuthorizationUtils.getHeaders(libraryConnectorXapiEditView);
          case 429:
              if(retryAfterSeconds!=0)
                  Thread.sleep(retryAfterSeconds);
          case 422: 
              failedAttempts=3;
          }
       }
      

      【讨论】:

      • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-01
      • 1970-01-01
      • 2020-11-29
      • 1970-01-01
      • 2021-12-26
      • 2011-05-12
      相关资源
      最近更新 更多