web-dev-qa-db-ja.com

SpringでRestTemplateクライアントに対してResourceAccessExceptionとHttpClientErrorExceptionをスローする

Apache Tomcat 8.5でSpring 4.3.1を使用して、GETを処理するRESTサーバー、POST&PUTリクエストを実装しました。POSTリクエストは次の形式で処理されます:

_@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Transactional
public Response postMethod(final MyDomain object) {
     domainHandler.createDomain(object);
     return Response.status(201).entity(object).build();
}
_

サーバー側でPOST要求を処理しているときに、WebApplicationExceptionがスローされます。

_@Provider
public class WebExceptionMapper implements ExceptionMapper<WebApplicationException> {
     @Override
     public Response toResponse(WebApplicationException exception) {
          int httpStatus = exception.getResponse().getStatus();
          ErrorMessage em = new WebErrorMessage(exception.getMessage());
          return Response.status(httpStatus).entity(em).build();
     }
}
_

クライアント側:

_response = rest.exchange(requestURL, method, requestEntity, MyDomain.class);
_

resourceAccessExceptionがスローされます。

_2017-07-25 15:46:41,489 ERROR [com.my.code.web.presentation.ManagementController:63] (http-nio-8080-exec-7#34): Internal exception occured with cause:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/": Server returned HTTP response code: 500 for URL: http://localhost:8080/; nested exception is Java.io.IOException: Server returned HTTP response code: 500 for URL: http://localhost:8080/
     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.Java:633) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.client.RestTemplate.execute(RestTemplate.Java:580) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.client.RestTemplate.exchange(RestTemplate.Java:498) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at com.my.code.web.integration.client.rest.FeedbackRestClient.callForApiCreateFeedback(FeedbackRestClient.Java:218) ~[classes/:?]
     at com.my.code.web.integration.client.rest.FeedbackRestClient.pushFeedbackData(FeedbackRestClient.Java:70) ~[classes/:?]
     at com.my.code.web.presentation.FeedbackController.feedback(FeedbackController.Java:91) ~[classes/:?]
     at Sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source) ~[?:?]
     at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.8.0_131]
     at Java.lang.reflect.Method.invoke(Method.Java:498) ~[?:1.8.0_131]
     at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.Java:221) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.Java:136) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.Java:114) ~[spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.Java:827) ~[spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.Java:738) ~[spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.Java:85) ~[spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:963) [spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.Java:897) [spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:970) [spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.Java:861) [spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at javax.servlet.http.HttpServlet.service(HttpServlet.Java:635) [servlet-api.jar:?]
     at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.Java:846) [spring-webmvc-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at javax.servlet.http.HttpServlet.service(HttpServlet.Java:742) [servlet-api.jar:?]
     at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:231) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:166) [catalina.jar:8.5.16]
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.Java:197) [spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) [spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:193) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:166) [catalina.jar:8.5.16]
     at org.Apache.Tomcat.websocket.server.WsFilter.doFilter(WsFilter.Java:52) [Tomcat-websocket.jar:8.5.16]
     at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:193) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:166) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:198) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:96) [catalina.jar:8.5.16]
     at org.Apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.Java:478) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:140) [catalina.jar:8.5.16]
     at org.Apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:80) [catalina.jar:8.5.16]
     at org.Apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.Java:624) [catalina.jar:8.5.16]
     at org.Apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:87) [catalina.jar:8.5.16]
     at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:342) [catalina.jar:8.5.16]
     at org.Apache.coyote.http11.Http11Processor.service(Http11Processor.Java:799) [Tomcat-coyote.jar:8.5.16]
     at org.Apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.Java:66) [Tomcat-coyote.jar:8.5.16]
     at org.Apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.Java:868) [Tomcat-coyote.jar:8.5.16]
     at org.Apache.Tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.Java:1455) [Tomcat-coyote.jar:8.5.16]
     at org.Apache.Tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.Java:49) [Tomcat-coyote.jar:8.5.16]
     at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1142) [?:1.8.0_131]
     at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617) [?:1.8.0_131]
     at org.Apache.Tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.Java:61) [Tomcat-util.jar:8.5.16]
     at Java.lang.Thread.run(Thread.Java:748) [?:1.8.0_131]
Caused by: Java.io.IOException: Server returned HTTP response code: 400 for URL: http://localhost:8080/
     at Sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.Java:1876) ~[?:1.8.0_131]
     at Sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.Java:1474) ~[?:1.8.0_131]
     at org.springframework.http.client.SimpleClientHttpResponse.getBody(SimpleClientHttpResponse.Java:85) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at com.my.code.web.integration.client.rest.BufferingClientHttpResponseWrapper.getBody(BufferingClientHttpResponseWrapper.Java:46) ~[classes/:?]
     at com.my.code.web.integration.client.rest.LoggingRequestInterceptor.traceResponse(LoggingRequestInterceptor.Java:66) ~[classes/:?]
     at com.my.code.web.integration.client.rest.LoggingRequestInterceptor.intercept(LoggingRequestInterceptor.Java:34) ~[classes/:?]
     at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.Java:85) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.Java:69) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.Java:48) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.Java:53) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.Java:619) ~[spring-web-4.3.1.RELEASE.jar:4.3.1.RELEASE]
     ... 47 more
_

質問:

_org.springframework.web.client.ResourceAccessException_ではなく_org.springframework.web.client.HttpClientErrorException_例外がスローされるのはなぜですか?WebApplicationExceptionが発生したときにGETリクエストを処理するとどうなりますか?

ResourceAccessException例外には、getRawStatusCode ()getResponseHeaders()などのHTTPステータスを読み取るためのメソッドがありません。

12
Marcin

実際の応答コードではなく、IOExceptionをラップしているためです。

根本的な原因は、BufferingClientHttpResponseWrapperが最初にボディがあるかどうかをチェックせずにボディを読み取ろうとしているためであると思われます。

2
OrangeDog

Yasammezがコメントで言ったように、ResourceAccessExceptionのようなRestClientExceptionのサブクラスの代わりにHttpClientErrorExceptionを取得するのは 既知の修正済みのバグ です。 Spring 3.0.7で修正されました。

私ができる最善のことは、両方をキャッチして、ステータスコードではなくメッセージのみを要求することでした。

try {
    #method that calls restTemplate.getForObject(...) or similar
} catch (RestClientResponseException | ResourceAccessException e) {
    log.info("Failed to get remote resource because: " + e.getMessage());
}

また、2つの異なるcatchステートメントを作成し、1つのcatchで、より詳細なログを取得することもできます。

0
jeremysprofile