HTTP 200 は「URLが正しい」ことを意味しない — リンク監視の盲点

リンク切れ監視で「200が返ったから大丈夫」と判定していませんか。実際には、URLの一部が間違っていてもサーバーが 301 で正解へ転送してくれることがあります。転送を追う監視ツールから見ると、間違ったURLも正しいURLもまったく同じ「200」です。2026年8月4日に実測した結果をもとに、この盲点と検出方法を整理します。

この記事の実測について: 以下の HTTP ステータスは、2026年8月4日に筆者が curl で実際に取得した結果です。挙動はサービス側の実装変更で変わりうるため、参考にする際はご自身の環境で追試してください。手順は本文に記載しています。

リンク切れ監視が見落とすもの

社内のリンク集、記事内の参照リンク、ブックマークの棚卸し。URL が生きているかを機械的に確かめたいとき、多くの実装は次のことをします。

  1. URL に GET(または HEAD)を投げる
  2. リダイレクトを追う
  3. 最終的なステータスが 2xx なら「生きている」と記録する

この方法は「URL が壊れているか」は検出できますが、「URL が間違っているか」は検出できません。両者は違います。前者はサーバーが 404 を返す状態、後者はサーバーが親切に正解へ転送してくれるせいで、間違いのまま 200 が返る状態です。

実測:ユーザー名が間違っていても 200 が返る

記事URLに投稿者名が含まれるサービスでは、この現象が起きやすくなります。ある技術記事共有サービスで、実在する記事のスラッグを使い、パスのユーザー名部分だけを変えてアクセスした結果が次のとおりです(2026年8月4日測定)。

リクエストしたURLの形ステータスLocation
正しい投稿者名 + 実在するスラッグ200(なし)
別人の実在する投稿者名 + 実在するスラッグ301正しい投稿者のURL(?redirected=1 付き)
存在しない投稿者名 + 実在するスラッグ301同上
正しい投稿者名 + 存在しないスラッグ404(なし)

読み取れることは明快です。このサービスは記事をスラッグだけで解決しており、パスのユーザー名部分は権威を持っていません。存在しないユーザー名を書いても、実在する別人の名前を書いても、301 で真の所有者のURLへ吸収されます。逆に、スラッグが存在しなければユーザー名が正しくても 404 です。

リダイレクトを追う監視ツールから見ると、これらはすべて「最終 200」です。ユーザー名を書き間違えたリンクも、投稿者が改名した後の古いリンクも、まったく同じく健全に見えます。

なぜこの設計になるのか: 責めるべき挙動ではありません。ユーザーが名前を変えても過去のリンクを死なせない、という配慮の結果です。同じ発想は多くのサービスにあります。GitHub のユーザー名変更、各種SNSのハンドル変更、CMS の記事IDベースのパーマリンクなど、「URLの一部が飾りで、実体は別のキーで引かれている」構造は珍しくありません。問題は挙動ではなく、それを前提に検証していない監視側にあります。

何が困るのか

検出する方法1:リクエストしたURLと最終URLを比べる

いちばん簡単で、どのサービスにも効く方法です。リダイレクトを追ったうえで、最終URLが元のURLと一致しているかを確認します。curl なら %{url_effective} を出力すれば取れます。

# 追跡した最終URLとステータスを並べて出す
curl -sL -o /dev/null \
     -w 'status=%{http_code}\nfinal=%{url_effective}\n' \
     "$URL"

# リダイレクトを追わず、3xx をそのまま観測する
curl -s -o /dev/null \
     -w 'status=%{http_code}\nlocation=%{redirect_url}\n' \
     "$URL"

監視の判定を次のように分けると、見落としが消えます。

観測意味扱い
200、かつ最終URL=元のURLURLが正しく、生きているOK
200 だが最終URLが元のURLと異なる転送されている。元のURLは古いか誤っている要確認(リンクを最終URLへ更新する)
3xx(追わない設定で観測)同上要確認
4xx / 5xx壊れているNG

比較の際は、サービスが付ける追跡用クエリを無視するのを忘れないでください。上の実測では転送先に ?redirected=1 が付きます。これを含めたまま文字列比較すると、正しく更新した後も永久に「不一致」と判定され続けます。クエリを落としてから比べるか、既知のパラメータを除去してから比べます。

検出する方法2:公開APIで所有者を突き合わせる

URLの一致だけでは「誰の記事か」までは分かりません。サービスが公開APIを持っている場合、ユーザー名で記事一覧を取得し、そこに目的のスラッグが含まれるかを確かめるのが確実です。上のサービスには認証不要のエンドポイントがあり、2026年8月4日時点で次の形の JSON を返しました。

# ユーザー名を指定して記事一覧を取る(認証不要・2026-08-04 実測)
curl -s "https://zenn.dev/api/articles?username=<name>&order=latest"

# レスポンスの形(抜粋)
{
  "articles": [
    {
      "slug": "66fc12c8dc1f61",
      "path": "/<name>/articles/66fc12c8dc1f61",
      "published_at": "2026-08-04T09:31:15.165+09:00",
      "article_type": "tech",
      "user": { "username": "<name>" }
    }
  ]
}

この path は、そのユーザーの記事としての正規パスです。手元のリンク集にある URL のパスがここに含まれていなければ、ユーザー名が誤っている(あるいは記事の所有が移っている)と判定できます。ステータスコードでは絶対に分からない情報です。

公開APIを叩くときの礼儀: 認証不要でも、無制限に叩いてよいという意味ではありません。取得間隔を空ける、User-Agent に連絡先を含める、レスポンスをキャッシュして再取得を減らす、429 が返ったら止めて待つ、robots.txt と利用規約を読む。監視は継続的に走るので、1回のスクリプトより負荷が問題になりやすい点に注意してください。

一般化:URLのどの部分が「実体のキー」なのか

この話はひとつのサービスの癖ではなく、URL設計の一般的な性質です。多くのサイトで、URLは次の2種類の要素の組み合わせになっています。

自分が監視・集計しているURLについて、どこがキーでどこが飾りかを一度確かめておくと、誤検知と見落としの両方が減ります。確かめ方は簡単で、飾りだと思う部分をわざと壊してアクセスし、404 になるか 301 になるかを見るだけです。上の実測はまさにそれを行ったものです。

あわせて、リダイレクトの種類も見ておくと運用判断がしやすくなります。恒久的な移動(301 / 308)なら手元のリンクを書き換えるべきで、一時的な移動(302 / 307)なら書き換えるべきではありません。HTTP ステータスコード全体の整理は「HTTPステータスコード入門」にまとめています。

チェックリスト

  1. 監視ツールは最終URLを記録しているか。ステータスだけを見ていないか。
  2. 元のURLと最終URLを比較しているか。比較の前に追跡用クエリを除去しているか。
  3. 301 / 308 を「OK」ではなく「要更新」として扱っているか。
  4. URLに含まれる人名・カテゴリ名が正しいことを、URL以外の手段で確かめているか。
  5. APIを叩く監視は、間隔・User-Agent・キャッシュ・429 の扱いを決めているか。

実測の再現手順(2026年8月4日)

  • 実在する記事のスラッグを公開APIから取得: curl -s "https://zenn.dev/api/articles?order=latest"
  • ユーザー名部分を(1)正しい名前、(2)実在する別人の名前、(3)存在しない名前 に差し替えて curl -s -o /dev/null -w '%{http_code} %{redirect_url}' を実行
  • スラッグ部分を存在しない値に差し替えて同じ観測を実行
  • 転送先ページの <link rel="canonical"> が真の所有者のURL(クエリなし)を指していることを確認

上記はすべて筆者が実行した結果です。サービス側の実装は変わりうるため、恒久的な仕様ではありません。

よくある質問(FAQ)

リンク監視で200が返れば、そのURLは正しいと言えますか?

言えません。URLの一部が間違っていても、サーバーが301で正しいURLへ転送する設計になっていることがあります。リダイレクトを追う監視ツールから見ると最終ステータスは200になるため、間違ったURLも健全に見えます。

間違ったURLを検出するにはどうすればよいですか?

リクエストしたURLと最終URLを比較します。curl なら -w '%{url_effective}' で最終URLを取得できます。比較の前に、サービスが付ける追跡用クエリ(例: ?redirected=1)を除去してください。リダイレクトを追わずに3xxをそのまま観測する方法も有効です。

URLに含まれるユーザー名が正しいかは、どうやって確かめますか?

ステータスコードでは分かりません。サービスが公開APIを持っている場合は、ユーザー名で記事一覧を取得し、目的のスラッグがその中に含まれるかを突き合わせます。含まれていなければ、ユーザー名が誤っているか所有が移っています。

URLのどの部分が間違っても転送されるのかを、どう見極めますか?

飾りだと思う部分をわざと壊してアクセスし、404になるか301になるかを見ます。404になる部分が実体を引く「キー」、301で吸収される部分が人間向けの「飾り」です。

← 技術ブログ一覧へ戻る