我正在尝试记录每个请求的请求-响应对。 问题是,当响应代码为401时,ClientHttpResponse.getBody()引发ResourceAccessException,而我无法读取响应正文。
这是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;
下面的拦截器的最后一行抛出以下异常。
我该如何解决这个问题?
org.springframework.web.client.ResourceAccessException: I/O error on
POST request for"https://example.com/api/sessions": Server returned
HTTP response code: 401 for URL: https://example.com/api/sessions;
nested exception is java.io.IOException: Server returned HTTP response
code: 401 for URL: https://example.com.11/api/sessions
这是拦截器的相关部分。
@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"));
...
}
这是自定义错误处理程序
公共类RequestErrorHandler实现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 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);
}
}
您期望401的响应主体是什么?
实际上,服务器是否发送响应正文都没有关系。 ,如果它没有发送任何响应正文,我想将responseString设置为null。 但这会引发异常。
您是否看到了这个答案stackoverflow.com/a/47467572/4545442? 可能会有所帮助。
在错误消息Server returned HTTP response code: 401 for URL: https:example.com.11apisessions中。 这个网址是错字还是实际更改了要请求的网址?
另外,@ SalihErikci您确定response.getBody()而不是ByteStreams.toByteArray(..)引发异常吗? 因为如果引发了I / O异常,则rest模板倾向于将其包装为ResourceAccessException
使用HttpComponentsClientHttpRequestFactory代替SimpleClientHttpRequestFactory。
还向'org.apache.httpcomponents:httpclient添加依赖项。
当状态为401时,HttpComponentsClientHttpRequestFactory可以读取正文。
我尝试了您的解决方案,但它给了我以下异常:sun.security.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效证书路径
现在您还有另一个问题,与您的第一个问题并不严格相关。现在,您必须导入证书。也许有用的是这个stackoverflow.com/questions/33497874/
我不认为ResourceAccessException被response.getBody()抛出,相反,似乎是ByteStreams.toByteArray(...)正在发送null流作为响应。
如果response.getBody()是null或ByteStreams.toByteArray(),可以请尝试调试。 因为发生I / O错误时会引发RescourceAccessException。
当httpstatus不是200时,Spring RestTemplate作为默认值会生成一个错误。
在我过去的项目中,我所做的是向其余模板添加自定义org.springframework.web.client.ResponseErrorHandler。
您可以编写这样的类:
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
}
}
然后我将其添加到我的其余模板中:
XML配置样本
class="org.springframework.http.converter.StringHttpMessageConverter">
class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
class="org.springframework.http.converter.ResourceHttpMessageConverter" />
class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter" />
class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
Java配置
@Config
public class restTemplConfig {
@Bean
public RestTemplate restTempl() {
RestTemplate result = new RestTemplate();
//Add converters
//Add custom error handler
result.setErrorHandler(new SimpleRestErrorHandler());
}
}
我希望它有用
我已经有一个自定义处理程序并映射错误状态代码。但是在点击自定义错误处理程序之前,我在拦截器中得到了异常。
您可以发布resttemplate配置吗?
添加了resttemplate配置。
我看不到将ErrorHanlder添加到RestTemplate的位置
忘记添加该行。添加
这很奇怪..您也可以添加RequestErrorHandler吗?
我看到的是,当httpstatus代码不是2xx时,您总是会生成错误。这意味着在您的方案中,当服务发出401作为状态代码时,您将收到错误。我猜你应该改用hasError方法
但是代码甚至都没有转到代码的那部分。