URLのフラグメント識別子(#以後の文字列)でページを振り分ける必要がありました。 この場合サーバでなくブラウザで振り分ける必要があります。
経緯は、もともと同じページ内でスクロールさせるつもりだったが別ページに分ける仕様に変わった。
既にハッシュタグ#
付きのURLはQRコードで印刷されていたため、システムを修正しました。(期限がなくて大変だった。。)
この記事はその備忘録です。
フラグメント識別子(fragment identifier)
URLの#
に続く文字列はフラグメント識別子です。RFC3986
よく、目次やページ内のリンクで使われています。
タグのid
と同じ文字列を指定すると、ページ内の該当箇所にスクロールしてくれます。
これはアンカーリンク(anchor link)やハッシュリンクとも呼ばれている。
フラグメント識別子はサーバに届かない
当初の考えではApacheで#
を/
に変換してリダイレクトさせる予定でしたが、設定してもリダイレクトされない。
アクセスログのURLには#から先がなくなっていました。
明確な挙動について読み解けなかったんですが、#
より後ろの文字列はサーバに届かないようです。
URI#fragent?query=1
このようにクエリパラメータを#
以後に付けてしまうとサーバまで届かないのでご注意を。
フラグメント識別子によってページを振り分ける構成
フラグメント識別子はサーバに届かないことが分かりました。
そこで、#
より前のURLのページを用意しブラウザからリダイレクトさせるようにします。
例として、次のURLで考えます。
https://host.domain.com/page#target1
フラグメント識別子はtarget1
、target2
、target3
とあり、3つのページにリダイレクトさせます。
https://host.domain.com/page
はリダイレクトするだけのページです。
https://host.domain.com/page
のページを用意するhttps://host.domain.com/page/target1
、https://host.domain.com/page/target2
、https://host.domain.com/page/target3
のページを用意するhttps://host.domain.com/page
ではフラグメント識別子毎に各ページへリダイレクトさせる
https://host.domain.com/page#target1
でアクセスするとサーバと2往復することになってしまいますが、用意したページに辿りつけるため良しとします。
ブラウザでリダイレクトする
https://host.domain.com/page
の<head>
に以下のスクリプトを書きます。
<script type="text/javascript">
console.log(location.href); // https://host.domain.comn/page#target1
console.log(location.hash); // #target1
if(location.hash.length == 0 || location.hash === '#'){
// ②このページはリダイレクトするのみ
// block redirect loop
location.href = '/';
}else{
// ②各ページへリダイレクトする
location.href = location.href.replace('#', '/');
}
</script>
②では、URLを調べ#
を/
に変えてリダイレクトさせています。
フラグメント識別子がなくとも、#
はブラウザに残ります。
そのため、②のみだとURLがhttps://host.domain.com/page#
の場合にリダイレクトループしてしまいます。
これを回避するためトップページへリダイレクトしていますが、404や#
を除くだけの処理に変えても良さげ。
location.hash
はURLのうち、#
とそれに続くフラグメント識別子を収めた文字列です。
おわりに
ギリギリ期限に間に合いました。 URLの修正は大変ですので、早めに決めて連絡下さい。お願いします。
参考
- RFC3986
- 3.5. と4.1. が該当箇所。
- 残念ながら、タグにidがないためフラグメント識別子が使えない
- RFC3986 日本語訳の複製 #section-3.5
- こちらはフラグメント識別子が使える!
- ハイパーリンクを提供する - The Web KANZAKI
- フラグメント識別子に関してこの記事の解説が詳しい
- Location - MDN
- URL - MDN
- MDNでも
#
に続くURLの文字列はフラグメント識別子と明記
- MDNでも