--The default settings for Spring Boot return a Whitelabel Error Page or JSON when a 404 Not Found or 500 Internal Server Error occurs. --HTML is returned for access from a web browser --JSON is returned for access from machine clients such as curl --You can't stop JSON from being returned with your own error.html or error / 404.html --It is better to prepare a class that implements the ErrorController interface and customize the HTML and JSON returned when an error occurs. --This operation check environment: Java 11 + Spring Boot 2.2.1
When an error occurs, it is displayed as 404 Not Found.
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
*Error controller for the entire web application.
*Implementation class of the ErrorController interface.
*/
@Controller
@RequestMapping("/error") //Mapping to error page
public class MySimpleErrorController implements ErrorController {
/**
*Returns the path of the error page.
*
* @return Error page path
*/
@Override
public String getErrorPath() {
return "/error";
}
/**
*Returns a ModelAndView object for the response.
*
* @param req request information
* @param mav response information
* @ModelAndView object for return HTML response
*/
@RequestMapping
public ModelAndView error(HttpServletRequest req, ModelAndView mav) {
//404 Not Found for any error
//The stator code and output contents can be customized as needed.
mav.setStatus(HttpStatus.NOT_FOUND);
//Specify the view name
//Thymeleaf template src/main/resources/templates/error.Use html
mav.setViewName("error");
return mav;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
</body>
</html>
404 Not Found is now returned to the client instead of 500 Internal Server Error etc. when an error occurs. It also now returns HTML instead of JSON for access from machine clients such as curl.
$ curl --include http://localhost:8080/
HTTP/1.1 404
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: text/html;charset=UTF-8
Content-Language: ja-JP
Transfer-Encoding: chunked
Date: Mon, 18 Nov 2019 13:33:52 GMT
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
</body>
</html>
Build detailed error information so that you can select what to return to the client and output it to the log.
Spring Boot's DefaultErrorAttributes class makes it easy to build detailed error information.
DefaultErrorAttributes (Spring Boot Docs 2.2.1.RELEASE API)
Default implementation of ErrorAttributes. Provides the following attributes when possible:
・ Timestamp --The time that the errors were extracted ・ Status --The status code ・ Error --The error reason ・ Exception --The class name of the root exception (if configured) ・ Message --The exception message ・ Errors --Any ObjectErrors from a BindingResult exception ・ Trace --The exception stack trace ・ Path --The URL path when the exception was raised
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
*Error controller for the entire web application.
*Implementation class of the ErrorController interface.
*/
@Controller
@RequestMapping("/error") //Mapping to error page
public class MyDetailErrorController implements ErrorController {
/**
*Returns the path of the error page.
*
* @return Error page path
*/
@Override
public String getErrorPath() {
return "/error";
}
/**
*Extract error information.
*
* @param req request information
* @return error information
*/
private static Map<String, Object> getErrorAttributes(HttpServletRequest req) {
//Get detailed error information with the DefaultErrorAttributes class
ServletWebRequest swr = new ServletWebRequest(req);
DefaultErrorAttributes dea = new DefaultErrorAttributes(true);
return dea.getErrorAttributes(swr, true);
}
/**
*Determine the HTTP status for the response.
*
* @param req request information
* @HTTP status for return response
*/
private static HttpStatus getHttpStatus(HttpServletRequest req) {
//Determine HTTP status
//Here, all except 404 are set to 500.
Object statusCode = req.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
if (statusCode != null && statusCode.toString().equals("404")) {
status = HttpStatus.NOT_FOUND;
}
return status;
}
/**
*Returns a ModelAndView object for the HTML response.
*
* @param req request information
* @param mav response information
* @ModelAndView object for return HTML response
*/
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView myErrorHtml(HttpServletRequest req, ModelAndView mav) {
//Get error information
Map<String, Object> attr = getErrorAttributes(req);
//Determine HTTP status
HttpStatus status = getHttpStatus(req);
//Set HTTP status
mav.setStatus(status);
//Specify the view name
//Src for Thymeleaf template/main/resources/templates/error.html
mav.setViewName("error");
//Set the information you want to output
mav.addObject("status", status.value());
mav.addObject("timestamp", attr.get("timestamp"));
mav.addObject("error", attr.get("error"));
mav.addObject("exception", attr.get("exception"));
mav.addObject("message", attr.get("message"));
mav.addObject("errors", attr.get("errors"));
mav.addObject("trace", attr.get("trace"));
mav.addObject("path", attr.get("path"));
return mav;
}
/**
*Returns a ResponseEntity object for the JSON response.
*
* @param req request information
* @ResponseEntity object for return JSON response
*/
@RequestMapping
public ResponseEntity<Map<String, Object>> myErrorJson(HttpServletRequest req) {
//Get error information
Map<String, Object> attr = getErrorAttributes(req);
//Determine HTTP status
HttpStatus status = getHttpStatus(req);
//Set the information you want to output
Map<String, Object> body = new HashMap();
body.put("status", status.value());
body.put("timestamp", attr.get("timestamp"));
body.put("error", attr.get("error"));
body.put("exception", attr.get("exception"));
body.put("message", attr.get("message"));
body.put("errors", attr.get("errors"));
body.put("trace", attr.get("trace"));
body.put("path", attr.get("path"));
//Output information in JSON
return new ResponseEntity<>(body, status);
}
}
Outputs the value specified in the ErrorController interface implementation class.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>/error</title>
</head>
<body>
<div th:text="'timestamp: ' + ${timestamp}"></div>
<div th:text="'status: ' + ${status}"></div>
<div th:text="'error: ' + ${error}"></div>
<div th:text="'exception: ' + ${exception}"></div>
<div th:text="'message: ' + ${message}"></div>
<div th:text="'errors: ' + ${errors}"></div>
<div th:text="'trace: ' + ${trace}"></div>
<div th:text="'path: ' + ${path}"></div>
</body>
</html>
An example of returning a 500 Internal Server Error in HTML. Detailed error information is embedded in the HTML.
$ curl --include -H "accept: text/html" http://localhost:8080/sample
HTTP/1.1 500
Content-Type: text/html;charset=UTF-8
Content-Language: ja-JP
Transfer-Encoding: chunked
Date: Mon, 18 Nov 2019 13:55:21 GMT
Connection: close
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>/error</title>
</head>
<body>
<div>timestamp: Mon Nov 18 22:55:21 JST 2019</div>
<div>status: 500</div>
<div>error: Internal Server Error</div>
<div>exception: java.lang.RuntimeException</div>
<div>message: This is a sample exception.</div>
<div>errors: null</div>
<div>trace: java.lang.RuntimeException: This is a sample exception.
at com.example.demo.DemoApplication.index(DemoApplication.java:18)
(The following is omitted)
An example of returning a 500 Internal Server Error in JSON. Detailed error information is included in the JSON.
$ curl --include http://localhost:8080/sample
HTTP/1.1 500
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 18 Nov 2019 13:55:31 GMT
Connection: close
{"exception":"java.lang.RuntimeException","path":"/sample","trace":"java.lang.RuntimeException: This is a sample exception.\n\tat com.example.demo.DemoApplication.index(DemoApplication.java:18)\n\t(Omission)java.base/java.lang.Thread.run(Thread.java:834)\n","error":"Internal Server Error","message":"This is a sample exception.","errors":null,"status":500,"timestamp":"2019-11-18T13:55:31.644+0000"}
-Spring Boot Whitelabel Error Page and JSON Response -Qiita -Customize the display when an error such as 404 Not Found occurs in Spring Boot -Qiita
Recommended Posts