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