エキサイト株式会社の中尾です。
RestControllerAdvice
で拾えない例外処理を拾う方法を記載します。
よくある方法は、ExceptionHandlerで全てcatchする方法だと思います。
@ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public String handleNotFoundException(Exception exception) { this.writeLog(exception.getStackTrace()); return "all Exception catch"; }
しかし、これだとResponseStatusが全てINTERNAL_SERVER_ERRORになります。 ResponseStatusを指定しない場合、ステータスOKになってしまいます。
なぜこのようなことしないといけないのでしょうか?
そもそもデフォルトのエラーレスポンスはいかになっています。
{ "timestamp": "2021-09-04T20:25:31.581+09:00", "status": 404, "error": "Not Found", "trace": "org.springframework.web.servlet.NoHandlerFoundException: No handler found for GET /aaa\n\tat org.springframework.web.servlet.DispatcherServlet.noHandlerFound(DispatcherServlet.java:1278)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1041)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:626)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.servlet.resource.ResourceUrlEncodingFilter.doFilter(ResourceUrlEncodingFilter.java:67)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:142)\n\tat org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.base/java.lang.Thread.run(Thread.java:834)\n", "message": "No handler found for GET /aaa", "path": "/aaa" }
エラー情報ですぎですよね。 本番環境でこれだと困ると思います。 以下の設定を追加することで、traceログを非表示にできます。
server.error.include-message: never server.error.include-binding-errors: never server.error.include-stacktrace: never server.error.include-exception: false
traceとmessageが消えました。
shogo.nakao@localhost: $ curl http://localhost:8080/aaa | jq [/Users/shogo.nakao] { "timestamp": "2021-09-04T20:34:27.516+09:00", "status": 404, "error": "Not Found", "path": "/aaa" }
しかし、アプリケーションによって、エラーレスポンスの形は変わると思います。 アプリケーションに合わせてエラーレスポンスを変えてあげましょう。
@Component @Profile("!local") public class CustomErrorAttributes extends DefaultErrorAttributes { /** * error response default setting * * @param webRequest * @param options * @return */ @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { final String message = this.getMessage(webRequest, this.getError(webRequest)); Map<String, Object> customErrorAttribute = new HashMap<>(); customErrorAttribute.put("error", new ErrorResponse.ErrorData() .setMessage(message)); return customErrorAttribute; } }
{ "error": { "message": 404 } }
解説します。
DefaultErrorAttributes
を継承することで、デフォルトエラーレスポンスの型を変えられます。
@Profile("!local")
を設定することでローカル環境以外の場合に適応させます。
ローカル環境では詳細なトレースログみたいですからね。
どっちにしてもコンソールログに詳細なログは出力されますが。
final String message = this.getMessage(webRequest, this.getError(webRequest));
こちらで、this.getMessageとthis.getErrorはDefaultErrorAttributes
の実装を見てください。