[JAVA] Minimale Anpassung der Spring Boot-Fehlerseite (Implementierung der ErrorController-Schnittstelle)

Überblick

--Spring Boot-Standardeinstellungen geben Whitelabel-Fehlerseite und JSON zurück, wenn 404 Not Found oder 500 Internal Server Error auftritt --HTML wird für den Zugriff über einen Webbrowser zurückgegeben --JSON wird für den Zugriff von Maschinenclients wie Curl zurückgegeben

Beispiel für die Implementierung einer minimalen Fehlerseite

Wenn ein Fehler auftritt, wird er als 404 Not Found angezeigt.

Minimale Implementierungsklasse der ErrorController-Schnittstelle

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;

/**
 *Fehlercontroller für die gesamte Webanwendung.
 *Implementierungsklasse der ErrorController-Schnittstelle.
 */
@Controller
@RequestMapping("/error") //Zuordnung zur Fehlerseite
public class MySimpleErrorController implements ErrorController {

  /**
   *Gibt den Pfad der Fehlerseite zurück.
   *
   * @Rückgabe des Fehlerseitenpfads
   */
  @Override
  public String getErrorPath() {
    return "/error";
  }

  /**
   *Gibt ein ModelAndView-Objekt für die Antwort zurück.
   *
   * @param req Anforderungsinformationen
   * @param mav Antwortinformationen
   * @ModelAndView-Objekt für die Rückgabe einer HTML-Antwort
   */
  @RequestMapping
  public ModelAndView error(HttpServletRequest req, ModelAndView mav) {

    //404 Für keinen Fehler gefunden
    //Der Statorcode und der Ausgabeinhalt können nach Bedarf angepasst werden.
    mav.setStatus(HttpStatus.NOT_FOUND);

    //Geben Sie den Namen der Ansicht an
    //Thymeleaf Vorlage src/main/resources/templates/error.Verwenden Sie HTML
    mav.setViewName("error");

    return mav;
  }
}

Thymeleaf HTML-Vorlagendatei src / main / resources / templates / error.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
</body>
</html>

Betriebsüberprüfung

404 Not Found wird jetzt an den Client zurückgegeben, anstatt 500 Internal Server Error usw., wenn ein Fehler auftritt. Es gibt jetzt auch HTML anstelle von JSON für den Zugriff von Maschinenclients wie Curl zurück.

$ 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>

Beispiel für die Implementierung einer Fehlerseite, das detaillierte Fehlerinformationen ausgibt

Erstellen Sie detaillierte Fehlerinformationen, damit Sie auswählen können, was an den Client zurückgegeben werden soll, und diese im Protokoll ausgeben können.

DefaultErrorAttributes-Klasse

Mit der DefaultErrorAttributes-Klasse von Spring Boot können auf einfache Weise detaillierte Fehlerinformationen erstellt werden.

DefaultErrorAttributes (Spring Boot Docs 2.2.1.RELEASE API)

Default implementation of ErrorAttributes. Provides the following attributes when possible:

・ Zeitstempel - Die Zeit, zu der die Fehler extrahiert wurden ・ Status - Der Statuscode ・ Fehler - Der Fehlergrund ・ Ausnahme - Der Klassenname der Stammausnahme (falls konfiguriert) ・ Nachricht - Die Ausnahmemeldung ・ Fehler - Alle ObjectErrors aus einer BindingResult-Ausnahme ・ Trace - Der Exception-Stack-Trace ・ Pfad - Der URL-Pfad, als die Ausnahme ausgelöst wurde

Implementierungsklasse der ErrorController-Schnittstelle

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;

/**
 *Fehlercontroller für die gesamte Webanwendung.
 *Implementierungsklasse der ErrorController-Schnittstelle.
 */
@Controller
@RequestMapping("/error") //Zuordnung zur Fehlerseite
public class MyDetailErrorController implements ErrorController {

  /**
   *Gibt den Pfad der Fehlerseite zurück.
   *
   * @Rückgabe des Fehlerseitenpfads
   */
  @Override
  public String getErrorPath() {
    return "/error";
  }

  /**
   *Fehlerinformationen extrahieren.
   *
   * @param req Anforderungsinformationen
   * @Fehlerinformationen zurückgeben
   */
  private static Map<String, Object> getErrorAttributes(HttpServletRequest req) {
    //Detaillierte Fehlerinformationen erhalten Sie mit der DefaultErrorAttributes-Klasse
    ServletWebRequest swr = new ServletWebRequest(req);
    DefaultErrorAttributes dea = new DefaultErrorAttributes(true);
    return dea.getErrorAttributes(swr, true);
  }

  /**
   *Bestimmen Sie den HTTP-Status für die Antwort.
   *
   * @param req Anforderungsinformationen
   * @HTTP-Status für die Rückantwort
   */
  private static HttpStatus getHttpStatus(HttpServletRequest req) {
    //Bestimmen Sie den HTTP-Status
    //Hier sind alle außer 404 auf 500 eingestellt.
    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;
  }

  /**
   *Gibt ein ModelAndView-Objekt für die HTML-Antwort zurück.
   *
   * @param req Anforderungsinformationen
   * @param mav Antwortinformationen
   * @ModelAndView-Objekt für die Rückgabe einer HTML-Antwort
   */
  @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
  public ModelAndView myErrorHtml(HttpServletRequest req, ModelAndView mav) {

    //Fehlerinformationen abrufen
    Map<String, Object> attr = getErrorAttributes(req);

    //Bestimmen Sie den HTTP-Status
    HttpStatus status = getHttpStatus(req);

    //Legen Sie den HTTP-Status fest
    mav.setStatus(status);

    //Geben Sie den Namen der Ansicht an
    //Src für Thymeleaf Vorlage/main/resources/templates/error.html
    mav.setViewName("error");

    //Legen Sie die Informationen fest, die Sie ausgeben möchten
    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;
  }

  /**
   *Gibt ein ResponseEntity-Objekt für die JSON-Antwort zurück.
   *
   * @param req Anforderungsinformationen
   * @ResponseEntity-Objekt für die Rückgabe der JSON-Antwort
   */
  @RequestMapping
  public ResponseEntity<Map<String, Object>> myErrorJson(HttpServletRequest req) {

    //Fehlerinformationen abrufen
    Map<String, Object> attr = getErrorAttributes(req);

    //Bestimmen Sie den HTTP-Status
    HttpStatus status = getHttpStatus(req);

    //Legen Sie die Informationen fest, die Sie ausgeben möchten
    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"));

    //Informationen in JSON ausgeben
    return new ResponseEntity<>(body, status);
  }
}

Thymeleaf HTML-Vorlagendatei src / main / resources / templates / error.html

Gibt den in der Implementierungsklasse der ErrorController-Schnittstelle angegebenen Wert aus.

<!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>

Betriebsüberprüfung

Ein Beispiel für die Rückgabe eines 500 Internal Server Error in HTML. Detaillierte Fehlerinformationen sind in HTML eingebettet.

$ 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)
(Folgendes wird weggelassen)

Ein Beispiel für die Rückgabe eines 500 Internal Server Error in JSON. Detaillierte Fehlerinformationen sind im JSON enthalten.

$ 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(Unterlassung)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"}

Referenzmaterial

Recommended Posts

Minimale Anpassung der Spring Boot-Fehlerseite (Implementierung der ErrorController-Schnittstelle)
Spring Boot Whitelabel-Fehlerseite und JSON-Antwort
[FCM] Implementierung der Nachrichtenübertragung mit FCM + Spring Boot
Ich möchte die Standardfehlermeldung von Spring Boot steuern
Unbekannter Fehler in Zeile 1 von pom.xml bei Verwendung von Spring Boot in Eclipse
Memorandum beim Spring Boot 1.5.10 → Spring Boot 2.0.0
Spring Boot + PostgreSQL-Fehlerbehebungsmethode
Nachricht erlöschen (Spring Boot)
Fehler bei der Implementierung bei der Implementierung der Spring-Validierung
WebMvcConfigurer-Memorandum von Spring Boot 2.0 (Spring 5)
Javaw.exe Fehler beim Starten von Spring Boot (STS)
Ab Spring Boot 2.3 enthält die Standardfehlerseite keine detaillierten Fehlerinformationen mehr