2009年2月2日月曜日

RoutingのパラメータにURLを指定したかったり

前回のエントリでFlickrから画像を取得する部分のコードに違和感を持った人がいますかね? ルートの登録でもアクションの定義でも"url"って書いてるのに、使ってないじゃないか!と。 そうなんですよ。

非同期サンプル書くのにURLを渡して、そのURLに対してWebRequest(WebClientでも)で取得するのを書こうとしてたんだけど、エラーになるのでとりあえずは固定で対応という逃げの一手。 で、どういうことかというと、例えばProxy(string url)という感じでアクションを定義(前回のサンプルだとSync2とAsync3)する感じ。

ルートの定義は

      routes.MapRoute(null,
       "Proxy/{*url}",
       new { controller = "WebRequest", action = "Proxy" }
     ); 

みたいな。 ※WebRequestControllerっていうのがいたとして。

リクエストするときのURLが昨日の例だと

http://localhost/Proxy/http://farm1.static.flickr.com/131/353753310_1ed04f694c_m.jpg

みたいな。 でも、そこはURLエンコードしとかないとさ、っていうんで

http://localhost/Proxy/http%3A%2F%2Ffarm1.static.flickr.com%2F131%2F353753310_1ed04f694c_m.jpg

みたいな。 でね、これがね、ダメなの。

img.aspx

ゴルァ~!っと怒られるわけっす。 ところで、このエラーいつだれが出してるんですかね? ってことで、調べてたんだけど、たぶんRouting(コレだ!っていう資料を見つけられなかった)。 WebServerじゃないと思うんだけどどうでしょう。 だってね。ASP.NET WebFormで以下のように書くとこれはちゃんととれるんだもん。

  public partial class _Default : System.Web.UI.Page
 {
   protected void Page_Load(object sender, EventArgs e)
   {
     if (!IsPostBack)
       var url = Request.QueryString["url"];
   }
 } 

何がまずいのかな~、と。

URL Encodingに書かれてる、使っちゃいけない文字も含まれて無いし。

だけど、MVCのRoutingってcontrollerとかactionとかっていうデータを構築してくれて、GetVirtualPathで勝手にURLエンコードした文字列返してくれるじゃないっすか。

VirtualPathData.VirtualPath プロパティ (System.Web.Routing)

その辺については特に書かれてないんだけど。 でも、Routeを登録するときにワイルドカード指定できるでしょ。 ワイルドカード内のスラッシュ'/'はエンコードしないじゃないですか。 もしやと、思って、UrlEncodeしないで試してみたんですよね。 もちろん':'は使えないんで除外します。

そしたらちゃんとリクエスト受け付けてくれるんですよ('/'を2個連続はダメだけど)。 http://localhost/Proxy/http/farm1.static.flickr.com/131/353753310_1ed04f694c_m.jpg このままだとアックションで取得出来るurlが"http/"で始まるんでちょっと感じ悪い。 ので、ルートの定義をちょっと変更。

      routes.MapRoute(null,
       "Proxy/{scheme}/{*url}",
       new { controller = "WebRequest", action = "Proxy" },
       new { scheme = @"(http|https)" }
     ); 

みたいな。 アクションの定義も。

    public ActionResult Proxy(string scheme, string url){...} 

みたいな。 このルートを使うようにHtml.ActionLinkを書いて出力させると、以下のように。

  <a href="/Proxy/http/farm1.static.flickr.com/131/353753310_1ed04f694c_m.jpg/">Flickr</a>

ふむ。

UrlEncodeしないとまずい文字を含めた、場合にどうなるかを試してみるのに、このUrlの最後に"/\<'09 in オレ>"をくっつけてみる。出力結果は↓。

  <a href="/Proxy/http/farm1.static.flickr.com/131/353753310_1ed04f694c_m.jpg/%5C%3C'09%20in%20%E3%82%AA%E3%83%AC%3E">Flickr</a>

ちゃんとUrlEncodeしてくれてる。 けど、これだとまた"Bad Request"。 まぁ、'\'とか'<','>'をエンコードしてるとはいえ、使っちゃってるのがいけないんだな、と。 そこはUrlEncodeしてるんだから通して欲しいけどね。ってことで、使用不可の文字を使ってる場合は、UrlEncodeしててもBad Requestになるので気をつけよう。

  <% = Html.ActionLink("Flickr", "Proxy", "WebRequest", new {
   scheme = "http",
   url = @"farm1.static.flickr.com/131/353753310_1ed04f694c_m.jpg/'09 in オレ"
   }, null)%>

↑こんな感じで、ActionLinkやUrl.Actionを使うのがいいみたい。 って、ことで実行結果は。 img.aspx2 img.aspx3

ASP.NET MVCは関係無いね。