読者です 読者をやめる 読者になる 読者になる

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

クロスドメインでWCF RESTを呼び出す方法。

WCF REST、便利ですねえ。
もちろんイントラ以外で使う場合はセキュリティとか考えないと行けないこと有ると思うんですが、開発用のツールをちょろっと作るのには非常に便利です。

というわけで今日作ってたのが、動作ログを取るツール。
・・・動作ログなんてコンソールに出してウィンドウから取ればいいじゃん、と思いますよね。まあ、普通はそうです。
でも、普通にコンソールウィンドウを見れないデバイスだって有るわけで。そういうののjavascriptデバッグのために、デバッグログをためておくサーバーを作ってたりしたわけです。
なんでホストサーバーにためないのかというと、まあサーバー側の都合で色々ありまして。

んで、そのときに問題になるのがまあクロスドメインのREST APIコールをどうするのかということ。
ご存じのようにドメイン外のXMLHttpリクエストは標準でははじかれてしまいます。
その壁を乗り越えるには、どうすればいいのか!?


なんて、大げさなことは必要ないです。
こちらの記事を参照で、すっきり解決。
Consuming WCF REST Services Using jQuery AJAX Calls - CodeProject

クロスドメインコールを呼べるようにするおまじないを、サーバー側に書いてやればよいだけです。
Global.asax.csのBeginRequestイベントハンドラを書き加えてやります。イベントハンドラを加えると言っても「Application_BeginRequest」という名前のメソッドを以下のように作ってやればOK。

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
 
                HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                HttpContext.Current.Response.Cache.SetNoStore();
                
                EnableCrossDmainAjaxCall();
        }
 
        private void EnableCrossDmainAjaxCall()
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
 
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", 
                              "GET, POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
                              "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age",
                              "1728000");
                HttpContext.Current.Response.End();
            }
        }

コードの意味は以下のように解説されています。以下意訳をさらっと。

  • AJAXコールを成功させるためには、ブラウザが"Access-Control-Allow-Origin"を応答ヘッダで受け取る必要がある。EnableCrossDmainAjaxCallメソッドの1行目はその処理を行う。
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");

ちなみに上記メソッドの第2引数("*"となっているもの)は応答ヘッダを付加するアドレスを指定できる。ここに特定のWebサイトドメインを記述すれば、許可されたサイトのみにアクセス許可を与えることができる。

  • もしブラウザがAjaxコールを安全でないと認識した場合(大概のAjaxコールはそれに当たりそう)、ブラウザは"preflighted"リクエストを実際のAjax呼び出しの前に送る。"preflighted"リクエストはOptionメソッドを用いるので、サーバーはOptionメソッドの要求を受けた場合には、"Access-Control-Allow-Methods"を用いてブラウザにAjaxコールで用いることができるメソッドを通知してやらないと行けない(上記例ではGETとPOSTのみしか使うことができなくなる)。また、"Access-Control-Allow-Headers"を用いて同じく使用可能なヘッダーも通知してやる必要がある。
  • また、"Access-Control-Max-Age"は"preflighted"された状態(安全が確認された状態)がどこまで保持されるかを定めている。

詳しいことは以下の原文を見てくださいませ。

  • For the "jQuery" "AJAX" calls to be successful, browsers must receive the response header "Access-Control-Allow-Origin", and the value of this header must identify the domain of the calling web application. If you want all the web pages from all the domains to access your services, you can set the value as "*".
  • If the browsers feel that your "AJAX" call is "un-safe", they will send a "preflighted" request to the server before they make the actual "AJAX" call. In this article, the call to the "OperationContract" "AddStudentToDepartment" uses a "POST" method, and the "content type" is "application/json", it is considered as "un-safe" by most browsers. The "preflighted" request uses the "OPTIONS" method. If the server receives an "OPTIONS" request, it needs to use "Access-Control-Allow-Methods" to inform the browser the HTTP methods allowed for the "AJAX" call. It also needs to use "Access-Control-Allow-Headers" to inform the browser the HTTP headers allowed in the actual "AJAX" call. In this article, the WCF REST Service allows the browsers to use "POST" and "GET" methods, and allows the headers "Content-Type" and "Accept" used in the "AJAX" call.
  • The value of the "Access-Control-Max-Age" tells the browsers how long the "preflighted" results remain valid, so when the browsers issue the same "AJAX" call again, they do not need to send the "OPTIONS" request before the "preflighted" results expire.