旧ブログの日本語URLからの301転送が、87本すべて効いていなかった話|Apacheはデコード後のパスで照合する
※ 本記事にはアフィリエイト広告(Amazonアソシエイト・楽天アフィリエイト等)が含まれています。
このブログは2026年7月末にWordPressから静的サイト(Astro)へ移行しました。移行の記事では「旧URLは全部301で新URLへ転送した」と書いています。嘘ではありません。.htaccess に87本、きちんと書いてありました。
ところが移行から3週間後、Search Consoleを見ていて血の気が引きました。検索から来た人の87%が、旧URLに着地して404を見ていたのです。転送は1本も動いていませんでした。
書いてあるのに、動いていない
旧ブログの記事URLは日本語スラッグでした。/在外公館-派遣員-仕事/ のような形です。ブラウザのアドレスバーやSearch Consoleでは、これがパーセントエンコードされて /%e5%9c%a8%e5%a4%96... と表示されます。
私はSearch Consoleに出ている表記をそのまま .htaccess に貼りました。
Redirect 301 /%e5%9c%a8%e5%a4%96%e5%85%ac%e9%a4%a8-%e6%b4%be%e9%81%a3%e5%93%a1-%e4%bb%95%e4%ba%8b/ /blog/gaimushou.../
これが87本。書き終えてデプロイして、移行完了のつもりでいました。確認は「ブラウザで旧URLを開いたら新URLに飛んだ」の1回だけ。そのとき開いたのが、たまたまASCIIスラッグの記事だったのが運の尽きでした。
原因:Apacheはデコードしてから照合する
Search Consoleの表示回数が旧URLに集中していることに気づいて、ターミナルから直接確かめました。
curl -sSI "https://vynsen.net/在外公館-派遣員-仕事/"
返ってきたのは HTTP/2 404。転送どころか、何もマッチしていません。一方で、ASCIIスラッグの旧URLはちゃんと 301 が返ります。
理由はこうです。Apacheの Redirect や RedirectMatch(mod_alias)は、リクエストされたパスをパーセントデコードしたあとでパターンと照合します。つまり実際に比較されるのは /在外公館-派遣員-仕事/ という生のUTF-8文字列です。そこに /%e5%9c%a8... というパターンを当てても、文字列として一致するはずがありません。
直し方:生のUTF-8で書く
対処そのものは単純で、.htaccess に日本語をそのまま書くだけです。
Redirect 301 /在外公館-派遣員-仕事/ /blog/gaimushoutokakawarushigototoha-zaigaikoukanhakeninnoshikenta/
87本を書き換えて、今度は curl -sSI で確認しました。日本語スラッグの旧URLから 301 と location: ヘッダーが返るのを、1本ずつ目で見ています。
二つ目の罠:転送「先」は逆にエンコードしてはいけない
直したつもりで、もうひとつ踏みました。
旧ブログのタグページ(/tags/腸活/ など)も新サイトのタグページへ転送したかったので、転送先を /tags/%E8%85%B8%E6%B4%BB/ とエンコードして書きました。すると location ヘッダーがこうなります。
location: /tags/%25E8%2585%25B8%25E6%25B4%25BB/
% が %25 に化けています。Apacheは転送先のURLを組み立てるとき、% を「エスケープすべき文字」としてもう一度エンコードするのです。結果、存在しないURLへ飛んで404。
転送先も生のUTF-8で書くのが正解でした。照合パターン側も転送先側も、「ブラウザに見えている表記」ではなく「生の文字列」で書く。これが一貫したルールです。
検索流入はどう変わったか
直したのが8月13日。その後のSearch Consoleの推移です。
| 時点 | 新URLへのクリック | 旧URLへのクリック |
|---|---|---|
| 8月25日(過去3か月) | 17 | 67 |
| 9月2日(過去3か月) | 32 | 60 |
新URLが1週間で2倍、旧URLは減り始めました。Googleは正しい301を見つけると、評価を少しずつ新URLへ移していきます。3か月単位の集計なので数字の入れ替わりは緩やかですが、方向は明らかに変わりました。
9月に入ってからは1日あたりのクリックが7〜8月の約2倍になっています。これが全部リダイレクト修正の効果とは言い切れませんが、3週間も404を返していた期間と比べれば、少なくとも足を引っ張るものはなくなりました。
教訓:「書いてある」と「効いている」は別
今回の反省は3つです。
設定ファイルに書いてあることと、サーバーが実際にやっていることは別物。書き終えた時点では何も終わっていません。
確認はブラウザではなくcurlで。ブラウザは勝手にエンコードもデコードもするので、何が送られて何が返っているかが見えません。curl -sSI なら、ステータスコードと location ヘッダーがそのまま出ます。
サンプルは1本ではなく、種類ごとに。私はASCIIスラッグを1本見て安心しました。日本語スラッグ、タグページ、wwwありなし。種類が違えば別々に確認しないと意味がありません。
移行作業の全体像はWordPressをやめて静的サイトに移行した全記録に、移行後にLighthouseの点が落ちた話はLighthouse満点は「取る」より「保つ」が難しいに書いています。静的サイト移行は、移行した日より、そのあと1か月のほうがやることが多いです。