Ошибка подключения к Spring Boot не обнаруживается

#java #spring #spring-boot #exception #resttemplate

#java #весна #spring-boot #исключение #resttemplate

Вопрос:

Я использую RestTemplate для подключения к другой службе, и я перехватываю ConnectException, однако блок catch никогда не перехватывает его. Исключение выдается в строке result = RestTemplate.getForEntity(uri, String.class ) и в консоли я получаю это:

 java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_201]
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) ~[na:1.8.0_201]
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_201]
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_201]
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_201]
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_201]
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_201]
    at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_201]
    at java.net.Socket.connect(Socket.java:538) ~[na:1.8.0_201]
    at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_201]
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[na:1.8.0_201]
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[na:1.8.0_201]
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:1.8.0_201]
    at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[na:1.8.0_201]
    at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[na:1.8.0_201]
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1220) ~[na:1.8.0_201]
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1156) ~[na:1.8.0_201]
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1050) ~[na:1.8.0_201]
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:984) ~[na:1.8.0_201]
    at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:76) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:735) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:338) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at com.tdl.controller.ToDoNoteController.addUserToNote(ToDoNoteController.java:323) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_201]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_201]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.16.jar:9.0.16]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]
  

Ответ в Postman:

 {
    "timestamp": "2019-04-24T15:48:25.395 0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "I/O error on GET request for "http://friend:5000/users/Soras2@gmail.com": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect",
    "path": "/todos/1/users"
}
  

Сам метод:

 @PostMapping("/todos/{toDoNoteId}/users")
    public ResponseEntity<?> addUserToNote(@RequestBody User user,@PathVariable int toDoNoteId) throws JsonParseException, JsonMappingException, ConnectException, IOException{
        String email = user.getEmail();
        final String uri = "http://friend:5000/users/" email;
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> result =null;
        int statusCode=0;
        ObjectMapper mapper = new ObjectMapper();
        //ResponseEntity<String> result = restTemplate.getForEntity(uri, String.class);

        //return null;

        try { // If user exists we will just add it to our ToDoNote

             result = restTemplate.getForEntity(uri, String.class); // exception thrown here

             ResponsePojo pojo = mapper.readValue(result.getBody(), ResponsePojo.class);
             User userToRespond = new User(pojo.getData().getEmail(),pojo.getData().getFirstName(),pojo.getData().getLastName());
             ToDoNote toDoNote = toDoNoteService.getToDoNoteById(toDoNoteId);
             if(toDoNote.checkIfUserExists(userToRespond)==true) {
                    return new ResponseEntity<String>(""User already in this note"",HttpStatus.CONFLICT);
             }
                else {
                    toDoNoteService.getToDoNoteById(toDoNoteId).addUser(userToRespond);
                    return new ResponseEntity<User>(userToRespond,HttpStatus.CREATED);
                }

            //System.out.println("result"   result);


        }
        catch(ConnectException ex2) {
            System.out.println(ex2.getCause());
            return new ResponseEntity<String>(""Coudl not connect"",HttpStatus.CONFLICT);
        }

        catch (HttpClientErrorException ex) {
            System.out.println("value"  ex.getStatusCode().value());
            statusCode=ex.getStatusCode().value();     
        }


        try { // If user does not exist by the given email we can POST
            if(statusCode==404) {
                if(user.getEmail()==null || user.getFirstName()==null || user.getLastName()==null) {
                     return new ResponseEntity<String>(""Required fields are missing( required fields are email,firstName,LastName)"",HttpStatus.BAD_REQUEST);
                }
                final String uriPost = "http://friend:5000/users";
                result= restTemplate.postForEntity(uriPost, user, String.class);
                System.out.println("result"   result);

                ResponsePojo pojo = mapper.readValue(result.getBody(), ResponsePojo.class);
                User userToRespond = new User(pojo.getData().getEmail(),pojo.getData().getFirstName(),pojo.getData().getLastName());
                toDoNoteService.getToDoNoteById(toDoNoteId).addUser(userToRespond);
                return new ResponseEntity<User>(userToRespond,HttpStatus.CREATED);
            }
        }
            catch (HttpClientErrorException ex) {
                System.out.println("value"  ex.getStatusCode().value());
                return ResponseEntity.status(ex.getRawStatusCode()).headers(ex.getResponseHeaders())
                        .body(ex.getResponseBodyAsString());
            }
    // istryniau daug tu throws not sure if thats that good

        System.out.println("Rip");
        return null;

    }
  

Единственное, что сработало, это либо перехватывающее исключение, либо RestClientException, однако я хочу перехватить само ConnectException. Кто-нибудь знает, чего мне не хватает?

Ответ №1:

Это ключевая часть:

вложенным исключением является java.net.ConnectException

RestTemplate getForEntity выдает исключение RestClientException, которое оборачивает ConnectException. Это не похоже на ссылку на родительский тип — RestClientException не расширяет ConnectException, поэтому вы не можете просто попытаться перехватить обернутый тип.

Я не уверен, почему вы против перехвата Exception или RestClientException. Если бы я хотел иметь определенную логику только для обработки ConnectException, я бы перехватил исключение RestClientException, а затем проверил тип внутреннего исключения (перепрофилируя, если это не ConnectException.)

Итак, что-то вроде этого:

 try {
    response = restTemplate.getForEntity( ... );
    // omitted for brevity
} catch (RestClientException e) {
  if (e.getCause() instanceof ConnectException) {
    // handle connect exception 
    return ResponseEntity.status(HttpStatus.CONFLICT).body("Could not connect");
  }
  throw e; // rethrow if not a ConnectException
}
  

Комментарии:

1. Я вижу. Спасибо за объяснение и предложение о том, как обработать исключение.:) Кроме того, если, допустим, мне нужно будет перехватить больше вложенных исключений, есть ли более элегантный способ, чем несколько предложений if?

2. Вы могли бы установить свой собственный обработчик ошибок в шаблоне rest, по умолчанию он будет выдавать 400/500 ответов в качестве исключений, можете увидеть краткое изложение здесь. baeldung.com/spring-rest-template-error-handling

3. @DarrenForsythe Он не будет обрабатывать исключения ResourceAccessExceptios