2025年4月24日木曜日

location.search/href/hash:urlから複数のデータを取得する方法

「Hey,Scripting Cat!URLパラメータの取得の仕方を教えて!」


はい、urlからパラメータを取得する方法はいくつかあります
location.href フル URL(プロトコル、ホスト、パス、クエリ、ハッシュ
location.search 「?」以降の全てクエリ名を取得
location.hash 「#」以降の値を取得

URLの指定方法と取り出し方

http://url/a.htm?q=z3z7z9z9z9z9z0z9z8z34z0z9z9z14z1#1z2z3
上記の場合取得できるのは

【href】http://url/a.htm?q=z3z7z9z9z9z9z0z9z8z34z0z9z9z14z1#1z2z3
【search】?q=z3z7z9z9z9z9z0z9z8z34z0z9z9z14z1
【hash】#1z2z3

ハッシュは必ず最後にする必要があります。ハッシュの後にクエリ―パラメータを入れるとハッシュの内容として処理される為クエリを取得出来ません
ちなみに、処理でもハッシュ(hash)ですが、フラグメントと呼んだりもします。

クエリとハッシュの扱い方の違い

さて、取り出し方の前にそもそものurlパラメータに指定方法について
既に上に書いてはいますが2種類あります。

■クエリ(?クエリ名=aaa&クエリ名=bbb)

基本的にはクエリ指定は別のページとして扱います
つまりサーバーや検索エンジンは別々のURL(コンテンツが違うものとして)判定しようとします。
もっと言うとクエリが指定されているのにページの内容が全く同じか少ししか変化しない場合グーグル等検索エンジンなどからは複数のページで同じ内容のコンテンツが提供されていると判断されてランキング低下やインデックス優先度低下のリスクが上がります。
phpなのでページ内容が直接変更されるものは良いですが、javascriptのみで内容を変更するような場合はjavascriptが無い状態で基本ページを判定されるので注意が必要です(同じページなのにurlパラメータ違いで全てが別ページ扱いになり、重複ページのペナルティの可能性が高まる)
他には、次に説明するハッシュと違いリアルタイムでシームレスなURL変更は出来ません。
「location.search = "?q=ppp"」みたいにするとページをリロードをしてパラメータが更新されます。

■ハッシュ(#aaa)

クエリとは逆に同じページ内のリンクとして扱います
アンカーなどでページを上下させる方法などが一般的です。
ハッシュを使ってコンテンツをタブなどで切り替えるなどもありです。
ブラウザの履歴などには一応urlの履歴が残りますが、クライアント側(ブラウザ側)で処理している為、サーバー側からはハッシュの遷移が取得出来ません。
そのためページ遷移の判定を得るためにクエリを指定するパターンも結構あります。
しかし先に説明した通りグーグルなどはクエリ違いの同じページを嫌います。
また、ハッシュはページをリロードせずにリアルタイムでURLハッシュを変更可能です。

■URLの正規化(canonical)

canonicalタグ(カノニカルタグ)を使う事で(基本的にはパラメータなしを指定)パラメータの有無についてこのページが(コンテンツが重複してるページの)正規のページです。と、知らせるタグがあります。
ただし、完全な指定をするというものではないのでurl違いの同じ内容のページはない方が良いです。検索エンジンに知らせるだけで検索エンジンが申告通り判定するかは別問題)。


データの取り出し方

まぁなんも考えず上記のurlをの指定方法をみれば想像つくと思いますが「str.split(”z”)」すれば良いです。もちろん取り出したいデータが数値じゃなくアルファベットなら固定数値でsplitすれば良いです。
ちなみにhrefからパラメータを取り出す事も出来ますが、基本的にはsearch/hashで取り出しましょう。
そうしないとクエリを取り出したかったのにハッシュが取り込まれたりする可能性があります。

■パラメータの頭に区切りを入れる手法
ちなみに上記で区切りの頭にzを入れてますがこれは「q=z3z7z9z9z9z9z0」この「クエリ名=」が邪魔だからです。パラメータの一つ目[0]を必ず捨てる事でパラメータを直接splitして1番目から配列を回すだけで良い。必要なら0番目の要素を破棄も可能。
普通は「q=3z7z9z9z9z9z0」ですが、こうした場合は「=」以降で切り出しした後にsplitをするか配列後0番目の要素から要素[0].split("=")[1]とかでもこの要素0が空指定だった場合、要素[0].split("=")[1]ではエラーするので有無を判定してから切り出す必要がでたりします。
下記で推奨する正しいパラメータの抜き出し方もありますがクエリ名を知ってる必要があります(普通は知ってる)。今回の方法であればクエリ名が何であっても0番目を捨てるので雑にデータを抜き出せます。


正しいURLパラメータと正しい値の取り出し方

正直手間なのですが正しい指定と取り出し方もあります。
ちゃんするならこうした方が良いです。
http://url/a.htm?q1=aaa&q2=bbb&q3=10&q4=30&q5=200#abcd

データの取り出し方

// 現在の URL のクエリ文字列を取得
const url = new URL(location.href);
// 例: http://url/a.htm?q1=aaa&q2=bbb&q3=10&q4=30&q5=200#abcd
// クエリパラメータを取得
const params = new URLSearchParams(url.search);
// 各パラメータの値を取得
const q1 = params.get("q1"); // "aaa"
const q2 = params.get("q2"); // "bbb"
const q3 = params.get("q3"); // 10 (数値)
const q4 = params.get("q4"); // 30 (数値)
const q5 = params.get("q5"); // 200 (数値)
// フラグメントを取得
const fragment = url.hash.slice(1); // "abcd" (# を除去)
// 確認
console.log({ q1, q2, q3, q4, q5, fragment });

厳密な指定や取得が必要な場合はこうしてください。SEO的にもこちらが正しいです。
ただ、やはり少し手間なんですよね。20個以上パラメータが必要だったりするときに全てクエリ名を入れる必要があるし。

ちなみにクエリは重複指定も可能です
http://url/a.htm?q1=aaa&q1=bbb
みたいなパターンです。
const params = new URLSearchParams(url.search);
const q1 = params.get("q1"); // "aaa"
これだと実は1つ目しか取得出来ません。二つ目以降は無視されます。
勿論対処方法もあります。

const q1 = params.getAll("q1"); // ["aaa","bbb"]
手動で切り出す方法はいくらでもありますが基本的にはこの取り出し方が一番きれいだと思います。
なお、getAll は常に配列を返します。1つの中身でも配列です["要素値"]、無ければ[](空配列)です。

非推奨な話

一番最初に説明している通り実は「location.search」は「「?」以降の全てクエリ名を取得します。なので実は「?クエリ名=」って記述しなくてもパラメータを指定出来るし、urlからパラメータを取り出す事も可能です。
例えば上部ではでは「z」で区切っていたけど数字もアルファベットも使い切りたい時に区切り文字がない。そんな時に実はURLに「a.html?aaa?BBB?ddd?123?saf?777777?ss」みたいなURLを作っても別にページにアクセス出来なくなったりはしない。
さらに「location.search.split("?")」みたいな形でデータを取り出す事も可能。

まぁでも「やろうと思えば出来る」だけであって勿論非推奨です。
当然ながら一般的なURLパラメータ以外は検索エンジンにも嫌がられます。

0 件のコメント:

コメントを投稿