数日前、ブログを整理していて、公開すべきではなかった古い記事を1つ削除しました。zh 版を削除したあと、直接アクセスするときれいな 404 になっていたので、これで終わりだと思っていました。ところが、その記事は Google にしつこく残り、en と ja の URL もクリックするとまだ「生きて」いました。もう削除したのに、なぜまだ消えないのでしょうか。
根本原因をたどってみると、少し苦笑いするしかありませんでした。削除しきれていなかったのではなく、1つの多言語リダイレクトがこの死んだリンクを検索エンジンの中に**固定**していたのです。この種の「ゾンビ URL」は踏みやすく、しかも症状がかなりまぎらわしいので、記録しておきます。

症状: zh は 404、en/ja は 302
このブログは3言語で、1つの記事に zh / en / ja の3つの URL があります。削除したのは zh 版です。curl してみると、こうなりました。
zh → 404 (なくなった。正しい)
en → 302 → /zh/posts/<slug>/ (削除したばかりの zh へ飛ぶ)
ja → 302 → /zh/posts/<slug>/
en / ja の URL はまだ残っていて、しかも 302 で、すでに 404 になった zh ページへ飛んでいました。ユーザーがクリックしたときの体験は「いったん転送されて、それから 404」。Google から見ると、「この2つの URL はまだ存在していて、ただリダイレクトしているだけ」です。そのため、インデックスに残り続けました。コンテンツは消えているのに、外側の殻がきれいに消えていなかったのです。
調査: 共通ルールか、それともこの記事だけか
まず切り分けるべきことがありました。すべての /en/posts/* が /zh/ に飛ぶのかどうかです。もし共通のフォールバックルールなら、ただの「死んだリンクから死んだリンクへのリダイレクト」で、話はそこまで特殊ではありません。そこで、まったく存在しない slug を1つ試しました。
en/まったく存在しない-slug → 404
en/<この記事の-slug> → 302 → zh
差が出ました。適当に作った slug はそのまま 404 になりますが、この記事の en だけが 302 になります。つまり、共通ルールではなく、この特定のパスに記録が残っていて、それが zh へ飛ぶよう指示している、ということです。
さらに、コンテンツ層で本当に削除されているかも確認しました。公開 API からこの記事の3つの言語版をダウンロードしようとすると、すべて「見つからない」と返りました。sitemap にも見つかりません。コンテンツはたしかに消えています。問題は別の場所に絞られました。リダイレクト記録が、コンテンツより長く生きていたのです。
根本原因: リダイレクトが「タスク表」だけを信じ、コンテンツの生存を確認していなかった
このブログの多言語ロジックは、「ない言語は、ある言語へフォールバックする」というものです。/en/posts/<slug> をレンダリングするとき、en 版が存在しなければ、worker はローカライズタスク表を見にいきます。そこには「この記事の元言語は zh で、en/ja に翻訳する」という情報が記録されています。元が zh だとわかると、302 で /zh/posts/<slug> へ飛ばします。
問題はここでした。タスク表の「元は zh」という記録を信じたものの、その zh ページが今も生きているかを確認していませんでした。zh コンテンツを削除したとき、このローカライズタスクの記録は一緒に消されませんでした。そのため、元のコンテンツはないのに記録だけは残り、リダイレクトはそのまま動き、302 をたどった先が 404 になっていました。
この bug をひとことで言うと、リダイレクトが指していたのは「コンテンツがあるはずの場所」であって、「コンテンツが実際にある場所」ではなかった、ということです。コンテンツを削除したり移動したりすると、この種のリダイレクトは固定された死んだリンクになります。
修正: 飛ばす前に、到達先が生きているか確認する
変更はとても小さく、方向も明確でした。302 を決める前に、飛ばそうとしている元ページが本当に published で、private ではなく、削除もされていないかを確認します。isPublishedPostLive() というガードを追加しました。
元ページは live? はい → これまで通り 302 で飛ばす(正常な3言語フォールバック)
いいえ → 404 を返す(ユーザーとクローラーを行き止まりへ送らない)
デプロイ後にもう一度 curl すると、en / ja はどちらもきちんと 404 になりました。一方で、正常な、元がまだ存在する3言語フォールバックにはまったく影響がありませんでした。別の、zh 版だけがある記事で意図的に確認し、その en は通常どおり 302 になり、誤爆はありませんでした。
持ち帰れる2つの教訓
1つ目、301/302 で 404 に飛ばすのは、直接 404 より悪い。 直接 404 は、Google に「ここはもうないので、インデックスから削除して」と伝えるものです。しかし「404 にリダイレクトする」形だと、Google はそのリダイレクトする URL を引き続き観察し、死んだリンクがかえって残りやすくなります。ページを完全に消したいなら、その URL 自身にすっきり 404 または 410 を返させるべきです。1段リダイレクトを挟んで「きれいに処理」しようとしないことです。
2つ目、削除はすべての派生物へ連鎖させる。 1つのコンテンツを削除するとき、それにつながっているものは本文だけではありません。リダイレクト記録、ローカライズの対応、sitemap の項目、キャッシュもあります。どれか1つでも消し忘れると、ゾンビ URL の入口が1つ増えます。今回の落とし穴は、まさにローカライズタスク表が一緒に削除されなかったことでした。削除ロジックを書くときは、清掃リストを漏れなく作るべきです。さらに安全な保険としては、今回の修正のように、あらゆる「リダイレクト」や「参照」が使われる前に、到達先がまだ生きているかを検証することです。そこにあるはずだ、と仮定しないことです。
ものを削除するのは、想像より難しいものです。本当にきれいに消せたかどうかの基準は、「主となる記録がなくなった」ことではありません。それにつながるすべての道をたどっても、もうどこにも到達できないことです。

微信
支付宝
コメント
コメントは即時公開されますが、ポリシー違反時は非表示になる場合があります。