Urlのエンコードとデコードの方法(ASP.net C#)

C#

本題に入る前のぼやきです。RawUrlの命名が気に食わない。
普通にRawUrlと言ったらアクセスしたフルパスが入ると思うんですが、実際にはホストやポートを含まない部分のみが返されます。
queryStringをデコードしてUriオブジェクトに戻そうと思ったらRawUrlだとエラーになり、あれ?おかしい?と思ったらこういう事でした。

以下のUrlにアクセスしたと仮定して
var url = "http://160.251.74.83/?hoge=fuga"

HttpListenerContext context;
HttpListenerRequest request = context.Request

request.RawUrl
// => /?hoge=fuga

request.Url.OriginalString
// => http://160.251.74.83/?hoge=fuga

本題はここから。
Urlのエンコードとデコードは初心者にはわかりづらかったので、楽に実装する方法だけを記します。

Encodeする側は簡単です。適当に文字列をつなげて最後にUri.EscapeUriString()に投げてしまえばいいようにしてくれます。

Encodeする側

// まとめてQuery Stringをエンコードしたいとき。
var url = "http://160.251.74.83/?hoge=ふが"
var encodedUrl = Uri.EscapeUriString(url);

// 以下だとQueryString以外の部分もEncodeされてしまうので注意。
var encoded1 = Uri.EscapeDataString(url);
var encoded2 = HttpUtility.UrlEncode(url);

Decodeする側も特に難しくありません。
基本的にQueryStringのみを扱いたいと思うので、ParseQueryStringにUrl.Queryを渡してあげればOKです。ParseQueryStringの中でDecodeしてくれます(第2引数で指定。ない場合はUTF-8)。
返り値はNameValueCollectionですが、Dictionaryと同じようなものです。Getメソッドが追加されているため、これを使って該当するクエリを取り出します。

Decodeする側

// decodeされたフルパスが欲しい時(どっちでもよい)
var decodedUrl = HttpUtility.UrlDecode(context.Request.Url.OriginalString);
var decodedUrl2 = Uri.UnescapeDataString(context.Request.Url.OriginalString);

// QueryStringを扱いたい時
var queryDictionary = HttpUtility.ParseQueryString(context.Request.Url.Query);
var hoge = queryDictionary.Get("hoge");
// hoge => "ふが" ※該当なしの場合はNull

最初はエンコードデコードのタイミングが良く分からなかったので、Url.OriginalStringをデコードしてUriオブジェクトを作成して、それを使ってParseさせたりと回りくどいことをしてました。
頻用するからもっと簡単なはずだと思って調べてみると、やはりシンプルに実装できますね。

ハマりそうなポイントは半角スペースの扱いです。
HttpUtility.UrlEncodeは「+」に変換し、
Uri.EscapeUriString & EscapeDataStringは「%20」にエンコードします。

逆にデコード時にUriUnescapeDataStringは「+」を半角スペースに変換しないため、HttpUtilityとUriクラスを混ぜて使うと問題になる場合があります。
「%20」はどちらであっても変換されますので、エンコードで常にEscapeUriString使う分には問題なさそうです。が、実装者によって変わってしまうとデコード側でバグになるかもしれないので可能な限り統一しましょう。

コメント