携帯サイトで長過ぎるクエリ文字列をどうにか短くできないか、というときの対処法
携帯サイトを開発する際、クエリ文字列が長すぎてページを表示できないことがあります。例えばチェックボックス・ラジオボタンの数が多いのだが、リンク(aタグ)やget方式で値を引き渡さなければいけない場合がそうでしょう。
docomoの場合、URLエンコード後の文字長は最大512バイトとしています。SoftBankは1024バイトまでOKですが(auは公式の情報がありません)、3キャリア対応のサイト制作ならば自ずと512バイトが上限と決まります。注意すべきは、この上限がURLの長さだということ。つまりクエリ文字列はさらに短くないといけない。
長すぎるクエリ文字列は、値を引き継げるかどうかだけでなく、ページのデータ量としても問題です。一見情報量の少ないページに見えても、aタグに長いクエリ文字列が埋め込まれることによりHTMLのサイズが肥大します。このページに画像があったらどうしましょう?このようなリンクが1つ2つあるだけで、画像が見せられなくなるかもしれません。ラウンドアバウトなら容量オーバーしませんが、よりきれいな画像を見せられるように、HTMLサイズは小さくなるに越したことはないのです。
今回は、チェックボックスを使うページを例に、クエリ文字列を短くする方法と元の内容に戻す方法について紹介します。
関連記事:
例えばこういうサイトを想定
以下の例は架空のものですが、実際にあったケースに近いものです。
- 商品を検索するサイト
- チェックボックスで条件を指定する(20個から複数選択)
- マッチするものから、さらにカテゴリ別のリンクを辿って絞り込み結果に移動できる
- 検索結果からリンクする商品ページには「戻る」があり、検索結果ページに戻れる
3番・4番が厄介です。それまでの検索条件をクエリ文字列にして渡すということですから。
チェックボックスのクエリ文字列は以下のような感じです。選べば選ぶほど長くなります。さらに「ファッション>時計>女性用」といったカテゴリ、商品コードが加われると、上述したような「長すぎるクエリ文字列」問題が起きるかもしれません。
?check2=1&check8=1&check9=1&check10=1&check12=1&check13=1&check18=1&check19=1&check20=1
チェックボックスの値を、0と1の羅列で表現する
このクエリ文字列のうち、どこを短くできるか。まず思いつくのは、チェックボックスの値を繋げてしまうという方法。1~20までチェックボックスの値(オン:1、オフ:0)を順番に羅列すれば、これだけでもだいぶ変わります。 ?check=01000001110110000111
ただ、カテゴリをさらに辿ったら?チェックボックスの数が増えたら?キーワード絞込みが追加になったら?画像があったら?こういうケースも考えると、さらに短くしておきたい。
次なる手段は16進数表現
この0と1からなる2進数表現の文字列を16進数表現に変換します。20桁なら0~5桁に縮小されます。Javaの場合、Integerクラスのメソッドを使えば、16進数表現への変換が容易に可能です。
- public static int parseInt(String s, int radix)
- public static String toHexString(int i)
?check=41d87
/* 2進数表現から16進数表現に変換 */ // 基数2を指定して整数にする int dec = Integer.parseInt(binary, 2); // 16進数表現に変換 String hex = Integer.toHexString(dec);
今回は符号ビットを考慮する必要はありません。チェックボックスの数が32以上になる場合は、32桁未満になるように文字列を区切り、それぞれを変換することになります。
ちなみに、16進数に変換することを決める際、他にも候補がありました。
- 32進数、または62進数(数字+大小英字)変換を自作する
- Base64(org.apache.commons.codec.binary.Base64)を使う
自作はテストやデバッグの工数が懸念されたのでやめました。Base64の方は、2進数表現のビットパターンによってはURLエンコードされる記号(/、+)が入る可能性があり最終的な長さが予測しにくく、目視による確認も困難なので、結局16進にしました。
元の2進数表現に戻す
今度は基数16を指定してparseIntし、さらにそれを2進数表記の文字列にします。0~20桁の文字列になるので、このままでは何にチェックを入れたかが正しく判りません。20桁になるまでゼロパディングして桁をそろえる必要があります。
- public static String toBinaryString(int i)
復元した結果。元の2進数表現と一致しています。
01000001110110000111
/* 16進数表現から2進数表現に変換 */ String binary = ""; // 基数16を指定して整数にする int dec = Integer.parseInt(hex, 16); // 2進数表現に変換 String binary = Integer.toBinaryString(dec); // 長さ20になるまで先頭を0埋めする while (binary.length() < 20) { binary = "0" + binary; }
まとめ
携帯サイトはPCと違い、常にHTMLと画像の総データ量の懸念がつきまといます。見えない部分のデータ量を少しでも縮めておきたいときにお試しください。Javaのメソッドを紹介しましたが、ちょっと調べたところphp、rubyにも同じような関数/メソッドがあるようです。他の言語でも同じ方法を適用できると思います。