2014-10-31 10 views
11

Używam interfejsu RESTful JSON API przy użyciu funkcji Spring RestTemplate i Jacksona. W niektórych przypadkach możemy otrzymać Status 401 (Nieautoryzowane) odpowiedź z niestandardowym JSON ciała, która jest wyznaczona przez producenta API, a wygląda to tak:Jak przeanalizować treść odpowiedzi w języku Java, gdy żądanie HTTP ma status powrotu 401

{ 
    "code": 123, 
    "message": "Reason for the error" 
} 

Musimy przeanalizować ciało i użyć właściwości code w naszej logice biznesowej.

Jest to obiekt Java odpowiedź błąd musimy zanalizować do:

public class CustomError { 

    @JsonProperty 
    private Integer code; 
    @JsonProperty 
    private String message; 

    public Integer getCode() { 
     return code; 
    } 
    public String getMessage() { 
     return message; 
    } 
} 

A inny system obsługi błędów, aby to zrobić:

public class CustomErrorHandler extends DefaultResponseErrorHandler { 
    private RestTemplate restTemplate; 
    private ObjectMapper objectMapper; 
    private MappingJacksonHttpMessageConverter messageConverter; 


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

    @Override 
    public void handleError(final ClientHttpResponse response) throws IOException { 

     try { 
      CustomError error = 
       (CustomError) messageConverter.read(CustomError.class, response); 
      throw new CustomErrorIOException(error, error.getMessage()); 
     } catch (Exception e) { 
      // parsing failed, resort to default behavior 
      super.handleError(response); 
     } 
    } 
} 

Procedura obsługi błędu nie powiedzie się z HttpMessageNotReadableException w próbie blok:

"Nie można odczytać JSON: nie można ponowić próby z powodu autoryzacji serwera, w trybie strumieniowym"

To jak ja wysyłania żądań:

restTemplate.postForObject(url, pojoInstance, responseClass); 

Jeżeli ten sam wniosek został wykonany ze zwykłego starego programu klienckiego reszta, jak listonosz otrzyma oczekiwanej odpowiedzi JSON. Zakładam więc, że problem może dotyczyć implementacji Springa ClientHttpResponse, która w jakiś sposób nie pozwala na dostęp do treści odpowiedzi, w przypadku statusu 401.

Czy rzeczywiście można przeanalizować treść odpowiedzi?

Aktualizacja

Z tego, co badane, klasa RestTemplate wykorzystuje ClientHttpResponse co z kolei tworzy sun.net.www.protocol.http.HttpURLConnection który zapewnia strumień wejściowy. Jest tam, gdzie strumień wejściowy jest zaniedbane i IOException jest wyrzucany:

nie można powtórzyć ze względu na uwierzytelnianie serwera, w trybie strumieniowania

Więc Realizacja HttpURLConnection „s jest przyczyną problemu .

Czy uda się uniknąć tego problemu? Być może powinniśmy użyć alternatywnej implementacji, która nie ignoruje treści odpowiedzi w przypadku kodu statusu błędu? Czy możesz polecić jakieś alternatywy?

Odpowiedz

21

Spróbuj zastosować następujące podejście bez potrzeby stosowania niestandardowego programu obsługi. Chodzi o to, aby uzyskać odpowiedź jako ciąg z HttpStatusCodeException, a następnie można przekonwertować go do obiektu.Do przeliczenia Kiedyś przez Jacksona ObjectMapper:

 try { 

      restTemplate.postForObject(url, pojoInstance, responseClass); 

     } catch (HttpStatusCodeException e) { 

      if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) { 

       String responseString = e.getResponseBodyAsString(); 

       ObjectMapper mapper = new ObjectMapper(); 

       CustomError result = mapper.readValue(responseString, 
         CustomError.class); 
      } 
     } 

Aktualizacja: Użycie innej fabryce może również pomóc, ponieważ nie jest to błąd w domyślny związanej z danym numerze (patrz komentarz poniżej):

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); 
+4

Próbowałem tego rozwiązania, ale wygląda na to, że nie działa. Wyjątek jest faktycznie zgłaszany, ale strumień odpowiedzi nie zawiera żadnych danych. Jeśli spróbuję tego samego żądania z POSTMAN, ciało odpowiedzi zawiera ciało, więc wydaje się znowu problemem RestTemplate. – Nikolay

+3

Znalazłem błąd, który opisuje problem, który masz w https://jira.spring.io/browse/SPR-9999. Pochodzi z zeszłego roku, ale być może jeszcze nie zostało to naprawione. Sugeruje użycie innej fabryki, aby zastosować inną implementację klienta (szablon RestTemplate = new RestTemplate (nowy HttpComponentsClientHttpRequestFactory()); – Marios

+0

@Marios, dziękuję za twoje wysiłki.) Używałem wcześniej 'SimpleClientHttpConnectionFactory'. mnie przy użyciu 'HttpComponentsClientHttpRequestFactory' - być może wyżej wspomniany' sun.net.www.protocol.http.HttpURLConnection' nie jest przez niego używany –

Powiązane problemy