errorpage

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

errorpage

errorpage

原則

Principles

エラーページは見た目の案内ではなく、HTTP 上の事実を正しく伝えつつ、人間・検索エンジン・API クライアント・AI エージェントを次の行動へ導くインターフェース。
最優先はステータスコード。CDN、ロードバランサ、SDK、ブラウザ、クローラは主にレスポンスのステータス行で意味を判断する。本文の「404」という文字やフィールドは補助情報にすぎない。
存在しない URL に通常画面を 200 OK で返す soft 404 を作らない。HTTP 上は「そのリソースは存在する」と宣言することになり、クローラ、監視、SDK、キャッシュが誤った前提で動く。
http
undefined
Error pages should do more than provide visual guidance: they should accurately communicate facts at the HTTP level while guiding humans, search engines, API clients, and AI agents toward their next action.
The status code takes priority. CDNs, load balancers, SDKs, browsers, and crawlers primarily determine the meaning of a response from its status line. A “404” or status field in the body is only supplementary information.
Do not create a soft 404 by returning a regular page with 200 OK for a nonexistent URL. At the HTTP level, this declares that the resource exists, causing crawlers, monitoring systems, SDKs, and caches to operate on a false assumption.
http
undefined

すべて不適切

すべて不適切

HTTP/1.1 200 OK ← 本文に <h1>404 Not Found</h1> があっても無意味 HTTP/1.1 200 OK ← 本文が { "status": 404 } でも無意味 HTTP/1.1 302 Found ← 代替がないのにトップへ飛ばす Location: /

代替ページがないのにトップページや検索結果へリダイレクトしない。ユーザーには親切に見えるが、要求したリソースが移動したと誤認させる。代替が本当に等価なら 301 か 308、そうでなければ 404 か 410 の本文でナビゲーションを出す。

- https://www.rfc-editor.org/rfc/rfc9110.html
- https://www.rfc-editor.org/rfc/rfc9457.html
HTTP/1.1 200 OK ← 本文に <h1>404 Not Found</h1> があっても無意味 HTTP/1.1 200 OK ← 本文が { "status": 404 } でも無意味 HTTP/1.1 302 Found ← 代替がないのにトップへ飛ばす Location: /

Do not redirect to the homepage or search results when no replacement exists. It may appear user-friendly, but it misleads users into believing that the requested resource has moved. If the replacement is truly equivalent, use 301 or 308; otherwise, provide navigation in the body of a 404 or 410 response.

- https://www.rfc-editor.org/rfc/rfc9110.html
- https://www.rfc-editor.org/rfc/rfc9457.html

コードの選択

Selecting a Status Code

  • 404 Not Found — URL が誤っている、ルーティングされていない、存在確認ができない。現時点で表現がないという意味で、恒久削除までは明言しない。存在を明かしたくない場合にも使える。
  • 410 Gone — 過去に存在し、意図して恒久的に廃止した。戻す予定も代替先もないと確定している場合だけ選ぶ。
  • 301 Moved Permanently / 308 Permanent Redirect — 等価な移転先が確実にある場合のみ。
  • 503 Service Unavailable — メンテナンス、過負荷、依存先障害。一時的に利用不能。
  • 401 Unauthorized — 認証情報が必要、または不十分。
  • 403 Forbidden — 認証済みでもアクセス不可。
権限のないリソースを 404 で隠すか 403 や 401 で明示するかは、セキュリティ方針として全体で一貫させる。ページごとに揺らさない。
  • 404 Not Found — The URL is incorrect, has no route, or its existence cannot be confirmed. It indicates that no representation currently exists, without explicitly stating that the resource has been permanently removed. It can also be used when revealing the existence of a resource is undesirable.
  • 410 Gone — The resource existed in the past and has been intentionally and permanently retired. Choose it only when it is certain that the resource will not be restored and no replacement exists.
  • 301 Moved Permanently / 308 Permanent Redirect — Use only when a reliably equivalent destination exists.
  • 503 Service Unavailable — Maintenance, overload, or a dependency failure. The service is temporarily unavailable.
  • 401 Unauthorized — Authentication information is required or insufficient.
  • 403 Forbidden — Access is unavailable even when the requester is authenticated.
Whether an unauthorized resource is hidden with 404 or explicitly identified with 403 or 401 should be governed by a consistent security policy. Do not vary this behavior between pages.

実装順序

Implementation Order

  1. ルーティング層で、既知のページ・API・静的ファイル以外を捕捉する。
  2. 旧 URL から等価な新 URL への対応表だけを 301 か 308 にする。
  3. 廃止が確定した公開 URL だけを 410 にする。
  4. その他の未知 URL は 404 にする。
  5. Accept に応じて HTML、Markdown、application/problem+json の本文を出し分ける。
  6. Vary: Accept を付け、表現ごとのキャッシュ混同を防ぐ。
  7. 404 ログを収集し、参照元、頻出 URL、bot アクセスを見てリンク修正やリダイレクトに反映する。
  1. At the routing layer, capture requests other than those for known pages, APIs, and static files.
  2. Use 301 or 308 only for mappings from old URLs to equivalent new URLs.
  3. Use 410 only for public URLs whose retirement has been confirmed.
  4. Use 404 for all other unknown URLs.
  5. Select the response body—HTML, Markdown, or application/problem+json—according to Accept.
  6. Add Vary: Accept to prevent different representations from being confused in the cache.
  7. Collect 404 logs and examine referrers, frequently requested URLs, and bot traffic to guide link corrections and redirects.

HTML 表現

HTML Representation

html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>ページが見つかりません | Example</title>
    <meta name="robots" content="noindex">
  </head>
  <body>
    <main>
      <h1>ページが見つかりません</h1>
      <p>URL が間違っているか、ページが移動・削除された可能性があります。</p>
      <nav aria-label="次の操作">
        <a href="/">ホームへ戻る</a>
        <a href="/search">サイト内を検索</a>
        <a href="/docs/">ドキュメント</a>
        <a href="/sitemap.xml">サイトマップ</a>
      </nav>
    </main>
  </body>
</html>
  • 見つからないことを明記する。「エラーが起きました」だけでは原因が分からない。
  • ホーム、サイト内検索、主要カテゴリ、ドキュメント、問い合わせ先へのリンクを置く。
  • 要求 URL を画面に出すなら、クエリ文字列、トークン、メールアドレスをそのまま出さない。
  • ブランドに沿わせつつ、通常のコンテンツページと紛らわしくしない。
  • noindex は必須ではない。主目的は正しい 4xx を返すこと。404 テンプレート自体が検索結果に出るのを避けたいなら加えてよい。
  • robots.txt で存在しない URL 群のクロールを全面禁止しない。アクセスできなければ 404 や 410 という状態を確認できなくなる。不要ページを消すなら、正しい 404 と 410、サイトマップからの削除、内部リンク修正が先。
html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>ページが見つかりません | Example</title>
    <meta name="robots" content="noindex">
  </head>
  <body>
    <main>
      <h1>ページが見つかりません</h1>
      <p>URL が間違っているか、ページが移動・削除された可能性があります。</p>
      <nav aria-label="次の操作">
        <a href="/">ホームへ戻る</a>
        <a href="/search">サイト内を検索</a>
        <a href="/docs/">ドキュメント</a>
        <a href="/sitemap.xml">サイトマップ</a>
      </nav>
    </main>
  </body>
</html>
  • Explicitly state that the resource was not found. Saying only that an error occurred does not explain the cause.
  • Provide links to the homepage, site search, major categories, documentation, and contact information.
  • If displaying the requested URL, do not expose query strings, tokens, or email addresses unchanged.
  • Follow the brand style while ensuring that the error page is not confused with a regular content page.
  • noindex is not mandatory. The primary objective is to return the correct 4xx status. Add noindex if you want to prevent the 404 template itself from appearing in search results.
  • Do not use robots.txt to completely block crawling of groups of nonexistent URLs. Doing so makes it impossible to verify that they return 404 or 410. To remove unwanted pages, first provide correct 404 and 410 responses, remove them from the sitemap, and fix internal links.

API 表現

API Representation

RFC 9457 の Problem Details を使う。
http
HTTP/1.1 404 Not Found
Content-Type: application/problem+json; charset=utf-8
Cache-Control: no-store
json
{
  "type": "https://example.com/problems/resource-not-found",
  "title": "Resource not found",
  "status": 404,
  "detail": "No resource matches this URL. See https://example.com/docs/.",
  "instance": "urn:request:01JABC..."
}
  • 本文の status は助言的。実際の HTTP ステータス行と必ず同じ値にする。
  • detail はデバッグ情報ではなく、クライアントが問題を修正するための説明に集中させる。
  • クライアントが文字列を解析して制御フローを作らせない。判定は HTTP ステータスと安定した type URI で行う。
  • type URI には可能なら人間向けの説明文書を置く。
  • 未知の拡張フィールドをクライアントが無視できる形にする。
Use RFC 9457 Problem Details.
http
HTTP/1.1 404 Not Found
Content-Type: application/problem+json; charset=utf-8
Cache-Control: no-store
json
{
  "type": "https://example.com/problems/resource-not-found",
  "title": "Resource not found",
  "status": 404,
  "detail": "No resource matches this URL. See https://example.com/docs/.",
  "instance": "urn:request:01JABC..."
}
  • The status in the body is advisory. It must always match the actual HTTP status line.
  • The detail should explain how clients can correct the problem rather than expose debugging information.
  • Do not require clients to parse strings and use them for control flow. Decisions should be based on the HTTP status and a stable type URI.
  • When possible, make the type URI point to human-readable documentation.
  • Ensure that clients can safely ignore unknown extension fields.

Markdown 表現

Markdown Representation

エージェント向け。Markdown は 404 の代わりではなく、404 の本文表現の一つ。ステータスは常に 404 のまま。
http
HTTP/1.1 404 Not Found
Content-Type: text/markdown; charset=utf-8
Vary: Accept
Cache-Control: no-store
md
undefined
This representation is intended for agents. Markdown is not a replacement for 404; it is one possible body representation of a 404. The status must always remain 404.
http
HTTP/1.1 404 Not Found
Content-Type: text/markdown; charset=utf-8
Vary: Accept
Cache-Control: no-store
md
undefined

Not found

Not found

This URL does not exist.

HTML を期待するブラウザに Markdown だけを返さない。Accept で出し分ける。開発者向けサイト、API サイト、プロダクト文書では、失敗したリクエストが行き止まりにならないよう探索の起点を入れる。
This URL does not exist.

Do not return only Markdown to browsers that expect HTML. Use Accept-based content negotiation. Developer sites, API sites, and product documentation should provide discovery entry points so that failed requests do not become dead ends.

HEAD

HEAD

HEAD /does-not-exist は、本文を返さないだけで GET と同等のステータスを返す。HEAD レスポンスに本文は含まれない。
HEAD /does-not-exist returns the same status as GET but does not return a body. A HEAD response contains no body.

キャッシュ

Caching

404 と 410 はキャッシュされ得る。存在しない URL へのアクセスが大量にあるサイトでは有効だが、公開直後や短期間で復活し得るリソースまで長く保持すると事故になる。
  • 完全に廃止し復活しない URL — 410 と短〜中程度のキャッシュ。
  • typo、ランダム URL、動的に出現し得る URL — 404 に no-store か短い max-age。
  • 認可のために意図的に 404 を返す URL — 共有キャッシュ経由の情報漏えいを避けるため private, no-store。
  • CDN がある場合、ブラウザ、CDN、アプリケーションの 404 挙動を別々に確認する。
404 and 410 responses may be cached. This is useful on sites that receive large volumes of requests for nonexistent URLs, but retaining resources that may return shortly after publication or within a short period can cause incidents.
  • URLs that are completely retired and will never return — Use 410 with a short-to-medium cache lifetime.
  • Typos, random URLs, or dynamically generated URL spaces — Use 404 with no-store or a short max-age.
  • URLs that intentionally return 404 for authorization purposes — Use private, no-store to prevent information leakage through shared caches.
  • When a CDN is present, verify the 404 behavior of the browser, CDN, and application layers separately.

漏らさない

Do Not Leak Information

エラー本文に次を出さない。
  • スタックトレース、例外メッセージ、ソースマップ URL。
  • フレームワーク名とバージョン、内部 IP、ホスト名。
  • リポジトリパス、DB テーブル名、クラウドバケット名。
  • ユーザー ID、メールアドレス、セッション情報。
  • 「この非公開リソースは存在するが権限がない」と判別できる応答の差分。
Problem Details は実装のデバッグ情報を公開する仕組みではない。
Never include the following in an error body.
  • Stack traces, exception messages, or source map URLs.
  • Framework names and versions, internal IP addresses, or hostnames.
  • Repository paths, database table names, or cloud bucket names.
  • User IDs, email addresses, or session information.
  • Response differences that reveal that a nonpublic resource exists but the requester lacks permission.
Problem Details is not a mechanism for exposing implementation debugging information.

検証

Validation

sh
undefined
sh
undefined

ステータスだけ見る

ステータスだけ見る

curl -s -o /dev/null -w '%{http_code}\n' https://example.com/no-such-path
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/no-such-path

リダイレクトを追わず最初の応答を見る

リダイレクトを追わず最初の応答を見る

curl -sS -D - -o /dev/null https://example.com/no-such-path
curl -sS -D - -o /dev/null https://example.com/no-such-path

HEAD でも同じか

HEAD でも同じか

API 表現

API 表現

curl -sS -i -H 'Accept: application/problem+json' https://example.com/api/no-such-path
curl -sS -i -H 'Accept: application/problem+json' https://example.com/api/no-such-path

Markdown 表現

Markdown 表現

curl -sS -i -H 'Accept: text/markdown' https://example.com/no-such-path

確認する。

- ステータス行が本当に 404、または意図した 410 か。
- 意図しない 30x がないか。
- Content-Type が本文の実体と一致しているか。JSON なら application/problem+json か。
- 本文に status を入れているなら HTTP ステータスと一致しているか。
- HTML にユーザーが復帰できる導線があるか。Markdown のリンクが有効か。
- 本文に秘密情報や内部情報がないか。
- HEAD が本文なしで同じ失敗ステータスを返すか。
- CDN やプロキシを経由した本番ドメインでも同じ結果になるか。
curl -sS -i -H 'Accept: text/markdown' https://example.com/no-such-path

Verify the following.

- The status line is genuinely 404 or the intended 410.
- There are no unintended 30x responses.
- The Content-Type matches the actual body. For JSON, it should be application/problem+json.
- If the body includes a status field, it matches the HTTP status.
- The HTML provides users with a way to recover, and the Markdown links are valid.
- The body contains no secrets or internal information.
- HEAD returns the same failure status without a body.
- The result is identical when accessed through the production domain via a CDN or proxy.