エキサイト株式会社の中尾です。
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
の実装を見てください。