web-dev-qa-db-fra.com

ClientHttpResponse.getBody () lève l'exception ResourceAccessException lorsque le code de réponse est 401

J'essaie de consigner les paires requête-réponse pour chaque requête. Le problème est que lorsque le code de réponse est 401, ClientHttpResponse.getBody() lève une exception ResourceAccessException et je ne peux pas lire le corps de la réponse. 

Ceci est la configuration RestTemplate 

RestTemplate restTemplate = new RestTemplate();

// Added this requestFactory to make response object readable more than once.
ClientHttpRequestFactory requestFactory =
        new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
restTemplate.setRequestFactory(requestFactory);
restTemplate.getInterceptors().add(new RequestLoggingInterceptor(vCloudRequest.getAction(),httpHeaders));
    restTemplate.setErrorHandler(new RequestErrorHandler());

return restTemplate;

La dernière ligne de l'intercepteur ci-dessous lève l'exception suivante.

Comment puis-je résoudre ce problème?

org.springframework.web.client.ResourceAccessException: erreur d'E/S sur POST demande pour " https://example.com/api/sessions ": le serveur a renvoyé Code de réponse HTTP: 401 pour l'URL: https://example.com/api/sessions ; L'exception imbriquée est Java.io.IOException: le serveur a renvoyé une réponse HTTP code: 401 pour l'URL: https: //exemple.com.11/api/sessions

Ceci est la partie liée de l'intercepteur.

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    ClientHttpResponse response = execution.execute(request, body);

    String requestString = new String(body);

    // Calling this method because when we make a POST or PUT request and get an error
    // response.getBody() throws IOException. But if we call response.getStatusCode() it works fine.
    // I don't know the reason.
    // I asked a question on stackoverflow
    // https://stackoverflow.com/questions/47429978/resttemplate-response-getbody-throws-exception-on-4-and-5-errors-for-put-and
    response.getStatusCode();
    String responseString = new String(ByteStreams.toByteArray(response.getBody()), Charset.forName("UTF-8"));
...
}

C'est le gestionnaire d'erreur personnalisé

la classe publique RequestErrorHandler implémente ResponseErrorHandler {

@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
        if (!response.getStatusCode().is2xxSuccessful()) {
        return true;
    }
    return false;
}

@Override
public void handleError(ClientHttpResponse response) throws IOException {
    JAXBElement<ErrorType> root = null;

    try {
        JAXBContext jaxbContext = JAXBContext.newInstance(ErrorType.class);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

        root = jaxbUnmarshaller.unmarshal(new StreamSource(
                response.getBody()), ErrorType.class);
    } catch (JAXBException e) {
        throw new IOException("XML converting error. Cannot convert response to ErrorType");
    }

    ErrorType error = root.getValue();
    throw new VcloudException(error);
}
}
6
Salih Erikci

Utilisez HttpComponentsClientHttpRequestFactory au lieu de SimpleClientHttpRequestFactory.

Ajoutez également la dépendance à 'org.Apache.httpcomponents: httpclient.

HttpComponentsClientHttpRequestFactory peut lire le corps lorsque l'état est 401.

2
marok

Je ne pense pas que ResourceAccessException soit lancé par response.getBody(), mais plutôt que ByteStreams.toByteArray(...) envoie probablement un flux null en réponse.

Pouvez-vous s'il vous plaît essayer de déboguer si response.getBody() est null ou si c'est ByteStreams.toByteArray(). Parce que RescourceAccessException est levé lorsqu'une erreur d'E/S se produit.

0
D D

Spring RestTemplate par défaut génère une erreur lorsque httpstatus n'est pas 200.

Dans mon projet précédent, j'ai ajouté un org.springframework.web.client.ResponseErrorHandler personnalisé au modèle restant . Vous pouvez écrire une classe comme celle-ci:

public class SimpleRestErrorHandler implements ResponseErrorHandler
{
    private static final Logger logger = LoggerFactory.getLogger(SimpleRestErrorHandler.class.getName());
    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException
    {
        int statusCode = response.getStatusCode().value();
        if( logger.isDebugEnabled() )
        {

            logger.debug("STATUS CODE ["+statusCode+"] ");
        }
        //Generate Error only when HTTP Status code is 500
        if( statusCode == 500 )
        {

            return true;
        }
        return false;
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException
    {
      //Here you can manage the error (in this sample only the http status code = 500
    }

}

Ensuite, j'ai ajouté ceci à mon modèle de repos:

Exemple de configuration XML

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">        <constructor-arg ref="bufferingClientHttpRequestFactory" />         <property name="errorHandler" ref="simpleRestErrorHandler" />       <property name="messageConverters">             <list>
                <bean
                    class="org.springframework.http.converter.StringHttpMessageConverter">
                    <constructor-arg value="#{T(Java.nio.charset.Charset).forName('UTF-8')}" />
                </bean>
                <bean
                    class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
                <bean
                    class="org.springframework.http.converter.ResourceHttpMessageConverter" />
                <bean
                    class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
                <bean
                    class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter" />
                <bean
                    class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />
                <bean
                    class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
                <bean
                    class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />          </list>         </property>         <property name="interceptors">          <!-- Custom interceptors -->        </property>     </bean> <bean id="bufferingClientHttpRequestFactory" name="bufferingClientHttpRequestFactory"       class="org.springframework.http.client.BufferingClientHttpRequestFactory">      <constructor-arg ref="simpleReqFact" />     </bean> <bean id="simpleRestErrorHandler" class="handlers.SimpleRestErrorHandler" />

Java config

@Config
public class restTemplConfig {
 @Bean
 public RestTemplate restTempl() {
  RestTemplate result = new RestTemplate();
  //Add converters
  //Add custom error handler
  result.setErrorHandler(new SimpleRestErrorHandler());
 }
}

J'espère que c'est utile

0
Angelo Immediata