この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.
SEOタイトル: Spring Boot「Whitelabel Error Page」原因と対処|独自エラーページの実装方法

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>Spring Boot の <strong>Whitelabel Error Page</strong></li><li>原因: <strong>独自のエラーページ (/error マッピング)</strong>が定義されていないためのフォールバック表示</li><li>対処1: 独自エラーコントローラ <code>@Controller + /error</code> を実装</li><li>対処2: <code>application.properties</code> で <code>server.error.whitelabel.enabled=false</code></li><li>対処3: <code>src/main/resources/templates/error.html</code> を置く(Thymeleaf 自動マッピング)</li></ul></td></tr></table>
<h2>エラー画面</h2>

<p>Spring Boot アプリにアクセスして 404 / 500 等のエラーが発生したとき、以下のような無味乾燥なページが表示されます:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat May 15 12:34:56 JST 2024
There was an unexpected error (type=Not Found, status=404).</code></pre>
<h2>原因</h2>

<p>Spring Boot は<strong>デフォルトのフォールバック</strong>エラーページとして「Whitelabel Error Page」を表示します。これは:</p>

<ul>
<li>独自の <code>/error</code> コントローラが定義されていない</li>
<li>テンプレートエンジンの <code>error.html</code> も無い</li>
<li>結果として Spring Boot 内蔵の素っ気ない HTML が表示される</li>
</ul>

<p>本番では UX もブランディングも崩れるので独自エラーページに置き換えます。</p>

<h2>対処1: error.html を配置(Thymeleaf)</h2>

<p>もっとも簡単。<code>src/main/resources/templates/error.html</code> を作成するだけで Spring Boot が自動でマッピング:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="${status} + &apos; - &apos; + ${error}">エラー</title>
    <link rel="stylesheet" href="/css/style.css">
</head>
<body>
    <div class="error-container">
        <h1 th:text="${status}">500</h1>
        <h2 th:text="${error}">Internal Server Error</h2>
        <p th:if="${message}" th:text="${message}"></p>

        <div th:if="${trace}" class="trace">
            <pre th:text="${trace}"></pre>
        </div>

        <a href="/">トップに戻る</a>
    </div>
</body>
</html></code></pre>
<p>ステータスコードごとに別ファイルを置くと自動で振り分けられます:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">src/main/resources/templates/error/
├── 404.html         ← 404 専用
├── 500.html         ← 500 専用
└── ...

src/main/resources/templates/
└── error.html       ← その他すべて</code></pre>
<h2>対処2: ErrorController を実装</h2>

<p>テンプレートを使わず、コントローラで JSON 等を返す:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-java">import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;

@RestController
public class CustomErrorController implements ErrorController {

    @RequestMapping("/error")
    public Map<String, Object> handleError(HttpServletRequest request) {
        Integer status = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        String message = (String) request.getAttribute(RequestDispatcher.ERROR_MESSAGE);
        String path = (String) request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);

        Map<String, Object> response = new HashMap<>();
        response.put("status", status);
        response.put("error", message);
        response.put("path", path);
        response.put("timestamp", new Date());

        return response;
    }
}</code></pre>
<h2>対処3: @ControllerAdvice で例外を catch</h2>

<p>例外型ごとに細かく分岐したい場合(推奨):</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-java">import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
    }

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<ErrorResponse> handleForbidden(AccessDeniedException ex) {
        return ResponseEntity.status(HttpStatus.FORBIDDEN)
            .body(new ErrorResponse("FORBIDDEN", ex.getMessage()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
        log.error("Unexpected error", ex);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(new ErrorResponse("INTERNAL", "サーバエラーが発生しました"));
    }

    public record ErrorResponse(String code, String message) {}
}</code></pre>
<h2>対処4: Whitelabel を無効化</h2>

<p>独自のエラーハンドリングだけ使い、Spring の Whitelabel を完全に切る:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-properties"># application.properties
server.error.whitelabel.enabled=false

# エラー詳細表示の制御
server.error.include-stacktrace=on_param    # never / always / on_param / on_trace_param
server.error.include-message=on_param        # never / always / on_param
server.error.include-binding-errors=on_param
server.error.include-exception=false

# /error パスを変更
server.error.path=/api-error</code></pre>
<h2>本番 vs 開発でのエラー詳細制御</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-properties"># application-dev.properties (開発)
server.error.include-stacktrace=always
server.error.include-message=always
server.error.include-exception=true

# application-prod.properties (本番)
server.error.include-stacktrace=never        # 機密漏洩防止
server.error.include-message=never
server.error.include-exception=false</code></pre>
<h2>404 だけを別ハンドラに</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-java">// 404 専用ハンドラ
@ControllerAdvice
public class NotFoundHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    public ModelAndView handle404(NoHandlerFoundException ex) {
        ModelAndView mav = new ModelAndView("error/404");
        mav.setStatus(HttpStatus.NOT_FOUND);
        return mav;
    }
}

// application.properties で 404 例外を投げるように
// spring.mvc.throw-exception-if-no-handler-found=true
// spring.web.resources.add-mappings=false</code></pre>
<h2>JSON / HTML を自動切替</h2>

<p>同じ <code>/error</code> でも Accept ヘッダで HTML / JSON を切り替えるパターン:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-java">@Controller
public class CustomErrorController implements ErrorController {

    @RequestMapping(value = "/error", produces = MediaType.TEXT_HTML_VALUE)
    public String html(HttpServletRequest request, Model model) {
        // HTML テンプレートで返す
        Integer status = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        model.addAttribute("status", status);
        return "error";
    }

    @RequestMapping(value = "/error")
    @ResponseBody
    public Map<String, Object> json(HttpServletRequest request) {
        // JSON で返す(API リクエスト用)
        // ...
        return Map.of("status", status, "error", "...");
    }
}</code></pre>
<h2>関連</h2>

<ul>
<li><strong>HandlerInterceptor</strong> でエラー処理前にロギング・通知を挟める</li>
<li><strong>Spring Security の AccessDeniedHandler</strong>: 403 の独自処理</li>
<li><strong>RestControllerAdvice</strong>: API 専用の @ControllerAdvice</li>
<li><strong>ProblemDetail (RFC 9457)</strong>: Spring 6 / Boot 3 で標準化されたエラーレスポンス形式</li>
<li><strong>Actuator</strong>: 健全性チェック / エラー統計の収集</li>
</ul>