web-dev-qa-db-ja.com

Spring Resttemplateの例外処理

以下はコードスニペットです。基本的に、私はエラーコードが200以外のものであるとき例外を伝播しようとしています。

ResponseEntity<Object> response = restTemplate.exchange(url.toString().replace("{version}", version),
                    HttpMethod.POST, entity, Object.class);
            if(response.getStatusCode().value()!= 200){
                logger.debug("Encountered Error while Calling API");
                throw new ApplicationException();
            }

しかし、サーバーから500応答の場合、私は例外を受けています

org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.Java:94) ~[spring-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]

本当にtryテンプレートの交換方法をラップする必要がありますか?それでは、コードの目的は何でしょうか。

78
vaibhav

ResponseErrorHandlerを実装するクラスを作成し、そのインスタンスを使用して残りのテンプレートのエラー処理を設定します。

public class MyErrorHandler implements ResponseErrorHandler {
  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    // your error handling here
  }

  @Override
  public boolean hasError(ClientHttpResponse response) throws IOException {
     ...
  }
}

[...]

public static void main(String args[]) {
  RestTemplate restTemplate = new RestTemplate();
  restTemplate.setErrorHandler(new MyErrorHandler());
}

また、SpringにはクラスDefaultResponseErrorHandlerがあります。handleErrorメソッドをオーバーライドするだけの場合は、インターフェイスを実装する代わりにこれを拡張できます。

public class MyErrorHandler extends DefaultResponseErrorHandler {
  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    // your error handling here
  }
}

SpringでHTTPエラーがどのように処理されるかについては、 ソースコード をご覧ください。

91
carcaret

HttpStatusCodeException例外をキャッチする必要があります。

try {
    restTemplate.exchange(...);
} catch (HttpStatusCodeException exception) {
    int statusCode = exception.getStatusCode().value();
    ...
}
26
mekazu

Springはhttpエラーコードを巧妙に例外として扱い、あなたの例外処理コードがエラーを処理するためのコンテキストを持っていると仮定します。期待通りに機能するように交換するには、次のようにします。

    try {
        return restTemplate.exchange(url, httpMethod, httpEntity, String.class);
    } catch(HttpStatusCodeException e) {
        return ResponseEntity.status(e.getRawStatusCode()).headers(e.getResponseHeaders())
                .body(e.getResponseBodyAsString());
    }

これはレスポンスから期待されるすべての結果を返します。

18
austin cherlo

別の解決策は、この記事の最後に「enlian」と記載されているものです。 http://springinpractice.com/2013/10/07/handling-json-error-object-responses -with-springs-resttemplate

try{
     restTemplate.exchange(...)
} catch(HttpStatusCodeException e){
     String errorpayload = e.getResponseBodyAsString();
     //do whatever you want
} catch(RestClientException e){
     //no response payload, tell the user sth else 
}
8
Investigator

これらのチュートリアルや他のチュートリアルは私にとって役に立ちませんでした。 RestTemplateはがらくたです。私はこれを書いているので、他の人はこの恐ろしいことに時間を無駄にしないと考えています。私はrestTemplate.exchangeを呼び出して400ステータスコードを取得します。その行でも例外がスローされますが、それはHttpStatusCodeExceptionではなく、ResourceAccessExceptionです。 ObjectとStringを交換してみました。私はResponseErrorHandlerを含めてみましたが、これはまったく役に立ちません。

RestTemplateでも自分がやりたいことができないのは初めてではありませんし、長い間使っていません。時間を無駄にしないでください。

あなたは例えば使用することができます:

Apache HttpClient: https://mvnrepository.com/artifact/org.Apache.httpcomponents/httpclient

またはOkHttp3: https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp

5
Siamaster

RestTemplateでプール(http client factory)またはロードバランシング(eureka)メカニズムを使用する場合、クラスごとにnew RestTemplateを作成する贅沢はありません。もしあなたが複数のサービスを呼んでいるのであればsetErrorHandlerを使うことはできません。

この場合、HttpStatusCodeExceptionをキャッチするのがより良い選択肢のようです。

唯一の他の選択肢は、@Qualifierアノテーションを使って複数のRestTemplateインスタンスを定義することです。

また - これは私自身の好みです - 私はエラー処理が私の呼び出しにぴったりと寄り添っているのが好きです。

1
Hannes

Springは非常に非常に大きなhttpステータスコードのリストからあなたを抽象化します。それが例外の考え方です。 org.springframework.web.client.RestClientException階層を調べてください。

Httpレスポンスを扱うときに最も一般的な状況をマッピングするためのたくさんのクラスがあります。 httpコードリストは非常に大きく、各状況を処理するコードを作成したくないでしょう。しかし、例えば、HttpClientErrorExceptionサブ階層を調べてください。 4xx種類のエラーをマッピングするための例外が1つあります。あなたが深く行く必要があるなら、あなたはそれができます。しかし、HttpClientErrorExceptionをキャッチするだけで、不正なデータがサービスに提供されたあらゆる状況に対処できます。

DefaultResponseErrorHandlerは本当にシンプルでしっかりしています。応答ステータスコードが2xxファミリからではない場合、hasErrorメソッドに対して単にtrueを返します。

1
Perimosh

交換コードは以下の通りです

public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
            HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException

例外RestClientExceptionには、HttpClientErrorExceptionおよびHttpStatusCodeException例外があります。

そのためRestTempleteではHttpClientErrorExceptionHttpStatusCodeException例外が発生する可能性があります。例外オブジェクトでは、このようにして正確なエラーメッセージを得ることができます:exception.getResponseBodyAsString()

これがコード例です

public Object callToRestService(HttpMethod httpMethod, String url, Object requestObject, Class<?> responseObject) {

        printLog( "Url : " + url);
        printLog( "callToRestService Request : " + new GsonBuilder().setPrettyPrinting().create().toJson(requestObject));

        try {

            RestTemplate restTemplate = new RestTemplate();
            restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            restTemplate.getMessageConverters().add(new StringHttpMessageConverter());


            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);

            long start = System.currentTimeMillis();

            ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);

            printLog( "callToRestService Status : " + responseEntity.getStatusCodeValue());


            printLog( "callToRestService Body : " + new GsonBuilder().setPrettyPrinting().create().toJson(responseEntity.getBody()));

            long elapsedTime = System.currentTimeMillis() - start;
            printLog( "callToRestService Execution time: " + elapsedTime + " Milliseconds)");

            if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) {
                return responseEntity.getBody();
            }

        } catch (HttpClientErrorException exception) {
            printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
            //Handle exception here
        }catch (HttpStatusCodeException exception) {
            printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
            //Handle exception here
        }
        return null;
    }

これがコードの説明です

このメソッドでは、リクエストとレスポンスのクラスを渡す必要があります。このメソッドはリクエストされたオブジェクトとしてレスポンスを自動的に解析します。

まず第一にあなたはメッセージコンバータを追加する必要があります。

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

それならrequestHeaderを追加しなければなりません。これがコードです:

HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);

最後に、交換方法を呼び出す必要があります。

ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);

印刷用にGsonライブラリを使用しました。ここにgradleです:compile 'com.google.code.gson:gson:2.4'

以下のコードを呼び出して応答を得ることができます。

ResponseObject response=new RestExample().callToRestService(HttpMethod.POST,"URL_HERE",new RequestObject(),ResponseObject.class);

これは完全な作業コードです

import com.google.gson.GsonBuilder;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;


public class RestExample {

    public RestExample() {

    }

    public Object callToRestService(HttpMethod httpMethod, String url, Object requestObject, Class<?> responseObject) {

        printLog( "Url : " + url);
        printLog( "callToRestService Request : " + new GsonBuilder().setPrettyPrinting().create().toJson(requestObject));

        try {

            RestTemplate restTemplate = new RestTemplate();
            restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            restTemplate.getMessageConverters().add(new StringHttpMessageConverter());


            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);

            long start = System.currentTimeMillis();

            ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);

            printLog( "callToRestService Status : " + responseEntity.getStatusCodeValue());


            printLog( "callToRestService Body : " + new GsonBuilder().setPrettyPrinting().create().toJson(responseEntity.getBody()));

            long elapsedTime = System.currentTimeMillis() - start;
            printLog( "callToRestService Execution time: " + elapsedTime + " Milliseconds)");

            if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) {
                return responseEntity.getBody();
            }

        } catch (HttpClientErrorException exception) {
            printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
            //Handle exception here
        }catch (HttpStatusCodeException exception) {
            printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
            //Handle exception here
        }
        return null;
    }

    private void printLog(String message){
        System.out.println(message);
    }
}

ありがとう:)

0