#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