クエリ文字列に日本語を使用している場合、それをブラウザのアドレスバーから直接入力して要求をかけるのは問題がありそうです。
以下のような、日本語を含む URL をブラウザのアドレスバーに直接打ち込んで要求をかけると、ブラウザはどのような文字列をサーバーに送るでしょうか?
http://www.abc.com/日本語.aspx?data=日本語
下の画像は IE9 の場合で、Fiddler を使って HTTP-GET 要求をキャプチャし、HexView で表示したものです。サーバーに送信したバイト列を 16 進数で表したものと、その 16 進数に相当する ASCII コードの文字が表示されています。
ファイル名の "日本語" の方は UTF-8 が URL エンコード(ASCII 文字で %E6%97%A5 ... %AA%9E)されますが、クエリ文字列の方の "日本語" は Shift_JIS そのまま(反転表示したバイト列 93 FA 96 7B 8C EA)になっているのが見えるでしょうか。
IE9, Firefox 7, Chrome 15 で試してみましたが、ファイル名の方はいずれも UTF-8 の URL エンコードで同じ結果になりましたが、クエリ文字列の方はそれぞれ以下のように結果が異なりました。
ブラウザ |
クエリ文字列 |
IE9 |
Shift_JIS そのまま |
Firefox 7 |
Shift_JIS を URL エンコード |
Chrome 15 |
UTF-8 を URL エンコード |
ということは、サーバーが受信した文字列を UTF-8 として解釈する場合(ASP.NET のデフォルト)、上記のブラウザのうち Chrome しかクエリ文字列を正しく送信できないということになるようです。
では、アドレスバー直打ちではなく、以下のようなハイパーリンクをクリックするとブラウザはどのような要求をサーバーに送るでしょうか?
<a href="default.aspx?data=日本語">リンク</a>
IE は文字コードのバイト列を生のまま送ります。例えば、"日本語" というクエリ文字列の場合、ハイパーリンクのあるページのエンコーディングが Shift_JIS なら 93 fa 96 7b 8c ea、UTF-8 なら e6 97 a5 e6 9c ac e8 aa 9e となります。
Firfox と Chrome は URL エンコードしてから送ります。ただし、Shift_JIS の場合、2 バイト目が ASCII の非予約文字のときは、その文字をそのまま使用します。"日本語" の場合、"本" の 2 バイト目 7b が ASCII 文字で '{' に該当するので、結果は "%93%FA%96{%8C%EA" になります。
特殊な例かもしれませんが、BlogEngine.NET の場合 '{' という文字が問題で、内部で URL の書き換えを行う際に例外がスローされてサーバーエラーになってしまうという問題がありました。
このような予期しない問題を避けるために、サーバー側できちんと UrlEncode メソッドを使って URL エンコーディングした文字列("本" は "%96%7b" になります)を使うのがよさそうです。(ただし、アドレスバー直打ちされた場合はどうしようもありませんが)
ちなみに、URL 本体('?' の左側の文字列)は、アドレスバーへの直打ち、ハイパーリンクへの設定、ページに使用されているエンコーディングの違い、ブラウザの違い(IE9, Firefox 7, Chrome 15 しか試してませんが)などに関係なく UTF-8 の URL エンコーディングになります。
なので、BlogEngine.NET 2.0 の Tag cloud の問題 と 日本語の著者名の問題 で書きましたように、URL 本体の文字に URL エンコードしない日本語の文字列を使っていますが、今までのところ期待通りに動いています。運よく問題に遭遇していないだけという可能性は排除しきれませんが。(笑)