स्प्रिंग रेस्टेमप्लेट अपवाद हैंडलिंग


124

नीचे कोड स्निपेट है; मूल रूप से, मैं अपवाद को प्रचारित करने की कोशिश कर रहा हूं जब त्रुटि कोड 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]

क्या मुझे वास्तव में कोशिश में बाकी टेम्पलेट एक्सचेंज विधि को लपेटने की आवश्यकता है? फिर कोड का उद्देश्य क्या होगा?


कृपया ApplicationException () का कोड साझा करें
मुद्रासर

जवाबों:


128

आप एक ऐसा वर्ग बनाना चाहते हैं 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());
}

इसके अलावा, स्प्रिंग में वर्ग है DefaultResponseErrorHandler, जिसे आप इंटरफ़ेस को लागू करने के बजाय बढ़ा सकते हैं, यदि आप केवल handleErrorविधि को ओवरराइड करना चाहते हैं ।

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

कैसे HTTP त्रुटियों को संभालती है , इसका अंदाजा लगाने के लिए इसके स्रोत कोड पर एक नज़र डालें ।


1
मेरे पास RestTemplate का 1 उदाहरण है जो मैं अलग-अलग कॉल के लिए पुन: उपयोग करता हूं। मुझे अलग-अलग कॉल से त्रुटियों को संभालने की आवश्यकता है - जाहिरा तौर पर वैश्विक हैंडलर के साथ ऐसा करने का कोई तरीका नहीं है - मुझे आपके अनुरोध के साथ हैंडलर प्रदान करने की आवश्यकता है।
mvmn

4
इस त्रुटि हैंडलर के साथ मुझे हमेशा एक ResourceAccessExceptionकारण मिलता है एस RestTemplate.doExecuteकैच IOExceptionऔर थ्रो ए ResourceAccessException। मैं क्या गलत कर रहा हूं?
फेडेरिको बेलुची

मैं DefaultResponseErrorHandler का विस्तार करके इसे हल करने में सक्षम था।
क्रेंगुटा एस

48

आपको एक HttpStatusCodeExceptionअपवाद को पकड़ना चाहिए :

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

37
IMO प्रतिक्रिया को हमेशा एक उपयुक्त स्थिति कोड के साथ आना चाहिए, अन्यथा कोड का उद्देश्य क्या है।
वैभव

5
मुझे @vaibhav की आपत्ति को समझना निश्चित नहीं है: HttpStatusCodeException को पकड़ना एक गलत कोड के लिए नहीं है, लेकिन क्योंकि कई मामलों में एक अपवाद हमेशा फेंका जाता है और इसलिए यदि आपका (कोड == मान) कभी भी निष्पादित नहीं किया जा सकता है।
स्टेफानो स्कार्पेंटी

1
जावा में अपवाद बहुत महंगे हैं। यह सामयिक, अप्रत्याशित कारणों (इसलिए नाम) के लिए ठीक है, लेकिन इसके अलावा, आपको इसके बजाय अन्य समाधानों की तलाश करनी चाहिए।
अगस्तन होरवाथ

11
"बहुत क़ीमती"? HTTP कॉल करने से अधिक महंगा, कहना?
इडेडांटे

4
@RaffaelBecharaRameh - HttpStatusCodeException .getResponseBodyAsString () या HttpStatusCodeException.getResponseBodyAsByte.rray ()।
डेव

45

स्प्रिंग बड़ी चतुराई से http त्रुटि कोड को अपवाद मानता है, और मानता है कि आपके अपवाद हैंडलिंग कोड में त्रुटि को संभालने के लिए संदर्भ है। कार्य करने के लिए विनिमय के रूप में आप यह उम्मीद करेंगे, ऐसा करें:

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

यह प्रतिक्रिया से सभी अपेक्षित परिणाम लौटाएगा।


2
आपको डिफ़ॉल्ट SDK की तुलना में अलग-अलग HttpClient का उपयोग करने की आवश्यकता है, त्रुटियों के लिए प्रतिक्रिया शरीर पाने के लिए
रेज़र

26

एक अन्य समाधान इस पोस्ट के अंत में "enlian" द्वारा यहाँ वर्णित है: http://springinults.com/2013/10/07/handling-json-error-object-responses-with-springs-resttplateplate

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 
}

4
आपको डिफ़ॉल्ट SDK की तुलना में विभिन्न HttpClient का उपयोग करने की आवश्यकता है, त्रुटियों के लिए प्रतिक्रिया शरीर प्राप्त करने के लिए (उदाहरण के लिए अपाचे कॉमन्स HttpClient)
रेजर

17

स्प्रिंग आपको http स्थिति कोड की बहुत बहुत बड़ी सूची से अलग करता है। वह अपवादों का विचार है। Org.springframework.web.client.RestClientException पदानुक्रम पर एक नज़र डालें:

Http प्रतिक्रियाओं से निपटने के दौरान आपके पास सबसे सामान्य स्थितियों को मैप करने के लिए कक्षाओं का एक समूह है। Http कोड सूची वास्तव में बड़ी है, आप प्रत्येक स्थिति को संभालने के लिए कोड लिखना नहीं चाहेंगे। लेकिन उदाहरण के लिए, HttpClientErrorException उप-पदानुक्रम में एक नज़र डालें। आपके पास किसी भी 4xx तरह की त्रुटि को मैप करने के लिए एक एकल अपवाद है। यदि आपको गहरे जाने की आवश्यकता है, तो आप कर सकते हैं। लेकिन सिर्फ HttpClientErrorException को पकड़ने के साथ, आप किसी भी स्थिति को संभाल सकते हैं जहां सेवा को खराब डेटा प्रदान किया गया था।

DefaultResponseErrorHandler वास्तव में सरल और ठोस है। यदि प्रतिक्रिया स्थिति कोड 2xx के परिवार से नहीं है, तो यह हैसर विधि के लिए सही है।


यार, स्पष्टीकरण के लिए धन्यवाद। आपने इस पेड़ को अपवाद पदानुक्रम के साथ कैसे बनाया?
अकेले खड़े हों

1
अरे यार, मैंने ग्रहण का इस्तेमाल किया। टाइप खोजकर्ता खोलने के लिए बस कंट्रोल + शिफ्ट + टी दबाएं, और RestClientException टाइप करें। परिणामों से RestClientException पर डबल क्लिक करें, ग्रहण आपके लिए उस वर्ग को खोल देगा। फिर, माउस कर्सर को वर्ग के नाम पर रखें (जहां यह कहता है कि "सार्वजनिक वर्ग RestClientException ...", और नियंत्रण + टी। आप उस पदानुक्रम को देखेंगे।
Perimosh

क्या तुमने कोशिश की?
Perimosh

1
Intellij में Btw यह है: प्रोजेक्ट ट्री में क्लास पर क्लिक करें और Ctrl + Alt + U, या राइट माउस क्लिक करें -> आरेख बनाएँ
अकेले खड़े हों

3

यदि आप अपने साथ पूलिंग (http क्लाइंट फैक्ट्री) या लोड बैलेंसिंग (यूरेका) तंत्र का उपयोग करते हैं RestTemplate, तो आपके पास new RestTemplateप्रति वर्ग बनाने की लक्जरी नहीं होगी । यदि आप एक से अधिक सेवाओं पर कॉल कर रहे हैं, तो आप उपयोग नहीं कर सकते setErrorHandlerक्योंकि यदि आपके सभी अनुरोधों के लिए विश्व स्तर पर उपयोग किया जाएगा।

इस मामले में, HttpStatusCodeExceptionलगता है कि बेहतर विकल्प है।

आपके पास एकमात्र विकल्प है RestTemplateकि @Qualifierएनोटेशन का उपयोग करके कई उदाहरणों को परिभाषित करें ।

इसके अलावा - लेकिन यह मेरा खुद का स्वाद है - मुझे अपनी कॉल को कसकर दबाए रखने में मेरी त्रुटि पसंद है।


3

मैंने इसे नीचे दिया है:

try {
  response = restTemplate.postForEntity(requestUrl, new HttpEntity<>(requestBody, headers), String.class);
} catch (HttpStatusCodeException ex) {
  response = new ResponseEntity<String>(ex.getResponseBodyAsString(), ex.getResponseHeaders(), ex.getStatusCode());
}

1

विनिमय का कोड नीचे है :

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

अपवाद RestClientExceptionहै HttpClientErrorExceptionऔर HttpStatusCodeExceptionअपवाद।

तो RestTempleteवहाँ में गिरावट HttpClientErrorExceptionऔर HttpStatusCodeExceptionअपवाद हो सकता है। अपवाद वस्तु में आप इस तरह से सटीक त्रुटि संदेश प्राप्त कर सकते हैं: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);

प्रीटी प्रिंटिंग के लिए मैंने ग्सन लाइब्रेरी का इस्तेमाल किया। यहाँ ग्रेड है:compile 'com.google.code.gson:gson:2.4'

प्रतिक्रिया प्राप्त करने के लिए आप केवल bellow कोड को कॉल कर सकते हैं:

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);
    }
}

धन्यवाद :)


2
'org.springframework.web.client.HttpClientErrorException' 'org.springframework.web.client.ttpStatusCodeException' का एक उपवर्ग है। यदि आप पहले से ही HttpStatusCodeException को पकड़ रहे हैं और उपरोक्त दो अपवादों को संभालने में कुछ अलग नहीं कर रहे हैं तो आपको HttpClientErrorException को पकड़ने की आवश्यकता नहीं है।
प्रोटॉन-पुनरुत्थान

0

एक बहुत ही सरल उपाय हो सकता है:

try {
     requestEntity = RequestEntity
     .get(new URI("user String"));
    
    return restTemplate.exchange(requestEntity, String.class);
} catch (RestClientResponseException e) {
        return ResponseEntity.status(e.getRawStatusCode()).body(e.getResponseBodyAsString());
}

-1

यहां HTTPS के साथ मेरा POST तरीका है जो किसी भी प्रकार की खराब प्रतिक्रियाओं के लिए प्रतिक्रिया निकाय देता है।

public String postHTTPSRequest(String url,String requestJson)
{
    //SSL Context
    CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
    //Initiate REST Template
    RestTemplate restTemplate = new RestTemplate(requestFactory);
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    //Send the Request and get the response.
    HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
    ResponseEntity<String> response;
    String stringResponse = "";
    try {
        response = restTemplate.postForEntity(url, entity, String.class);
        stringResponse = response.getBody();
    }
    catch (HttpClientErrorException e)
    {
        stringResponse = e.getResponseBodyAsString();
    }
    return stringResponse;
}

3
आपको डिफ़ॉल्ट SDK की तुलना में विभिन्न HttpClient का उपयोग करने की आवश्यकता है, त्रुटियों के लिए प्रतिक्रिया शरीर प्राप्त करने के लिए (उदाहरण के लिए अपाचे कॉमन्स HttpClient)
रेजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.