クロスドメイン制約 を 回避 する クライアント & サーバー 実装 を XmlHttpRequest level2 の プリフライト を利用して実現します。
クロスドメイン通信 を実現するには "サーバー側" と "クライアント側" の2カ所に対して手を入れる必要があるかどうか考えます。 ここでは、"クライアント側" と "サーバー側" 両方に手を加えて クロスドメイン通信 を実現する方法を載せます。 具体的には、XmlHttpRequest level2 の プリフライト を利用して クロスドメイン通信 を行えるようにします。
想定する クロスドメイン通信 環境
サーバーA から HTML & JavaScript を受信し、足りない リソース を サーバーB から取得する環境を想定します。
GET はそのまま通信されますが、POST, PUT, DELETE は プリフライト (OPTIONS) が自動的に行われます。 つまり、自前で OPTIONS を実行しなくても勝手に実行されるので、自動的に行われる プリフライト通信 に正しい応答処理が行われるようにすれば良いことになります。
サーバー 実装
サーバー側では、"プリフライトの応答" と "サービスの実態" の 2つ を記述します。 サーバー側で確認、実装が必要なのでは以下に示す2ファイル(WebApiConfig.cs、CatalogController.cs)です。
以下にサーバー側で必要な実装の内容、手順を載せます。
- OPTIONS へのマッピング を確認。
/App_Start/WebApiConfig.cs12345678public
static
void
Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name:
"DefaultApi"
,
routeTemplate:
"api/{controller}/{id}"
,
defaults:
new
{ id = RouteParameter.Optional }
);
}
- プリフライト 用 の コード を 実装。
/Controllers/CatalogController.cs12345678910// OPTIONS api/catalog
public
void
Options()
{
var response = HttpContext.Current.Response;
response.AppendHeader(
"Access-Control-Allow-Methods"
,
"GET, POST, PUT, DELETE, OPTIONS"
);
response.AppendHeader(
"Access-Control-Allow-Headers"
,
"X-PINGOTHER, application/json"
);
response.AppendHeader(
"Access-Control-Max-Age"
,
"1728000"
);
}
- GET, POST 等 実態 コード を 実装。
(※ここでは POST を サンプルコード として掲載します。その他は、サーバー実装(全体) サンプルコードをご参照ください。)
/Controllers/CatalogController.cs12345678// POST api/catalog
public
string
Post([FromBody]
string
value)
{
var response = HttpContext.Current.Response;
return
"success POST method !!"
;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | namespace CrossOriginResourceSharing.Controllers { using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web; public class CatalogController : ApiController { // GET: api/catalog public IEnumerable< string > Get() { var response = HttpContext.Current.Response; return new string [] { "val1" , "val2" }; } // GET api/catalog/5 public string Get( int id) { var response = HttpContext.Current.Response; return "value" ; } // POST api/catalog public string Post([FromBody] string value) { var response = HttpContext.Current.Response; return "success POST method !!" ; } // PUT api/catalog/5 public string Put( int id, [FromBody] string value) { var response = HttpContext.Current.Response; return "success PUT method !!" ; } // DELETE api/catalog/5 public void Delete( int id) { var response = HttpContext.Current.Response; } // OPTIONS api/catalog public void Options() { var response = HttpContext.Current.Response; response.AppendHeader( "Access-Control-Allow-Methods" , "GET, POST, PUT, DELETE, OPTIONS" ); response.AppendHeader( "Access-Control-Allow-Headers" , "X-PINGOTHER, application/json" ); response.AppendHeader( "Access-Control-Max-Age" , "1728000" ); } } } |
クライアント 実装
クロスドメイン通信 は、実際に行う前に OPTION 通信で クロスドメイン通信 の許可を取った(プリフライト)のち、 はじめて クロスドメイン通信 ができるようになります。 この事前に行われる OPTION通信 は、自前で実装するのではなく、ブラウザの処理で自動的に処理されるようです。 つまり、以下のような処理の流れになります。
- クライアントからクロスドメイン通信を試みる
- ブラウザが自動で プリフライト (OPTION通信) を行う
- クロスドメイン通信ができそうなので、再度リクエストする
実装してみると、以下のような 単純な サンプルコード になります。 これだけで、OPTION と POST が行われます。
1 2 3 4 5 6 7 8 9 10 | function () { $.ajax({ type: 'POST' , }).done( function (data, textStatus, jqXHR) { window.alert(JSON.stringify(data)); }).fail( function (jqXHR, textStatus, errorThrown) { window.alert(errorThrown); }); }; |
今回、以下のサイトを参考にしました。
- W3C - Cross-Origin Resource Sharing
- MSDN - XMLHttpRequest の拡張機能
- IEBlog - CORS for XHR in IE10
- MDN - HTTP access control (CORS)
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!