先說下需求:在原來的WebApi項目中增加對js跨域的請求支持,請求方式:以POST為主,webapi路由規則根據原項目需求修改如下:
public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); }
熟悉WebApi的猿猿們都知道這樣設置路由規則直接導致了同一個controller中的不同方法的訪問改由方法前的標簽決定,而不是方法名來決定。
關於js跨域的原理如下:假設我們請求的地址A:http://api.xx.com/api/GetAllPeople,那如果在B頁面 http://www.baidu.com/tlzzu.html中使用POST去調用外部接口的話,B頁面會先向A地址發送一個OPTIONS類型(OPTIONS並不是webapi中的一個方法名,而是一種請求類型,類似POST、GET等)的預檢請求(Preflight Request)只要對這種請求返回200就可以,具體內容不作檢驗。執行成功后會再次對A接口進行正常請求。返回數據。
解決辦法:
如果是Asp.Net MVC或者是WebApi可進行如下設置:
1.先在Web.config中進行如下設置:
<system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /><add name="Access-Control-Allow-Headers" value="Origin,X-Requested-With,Content-Type,accept,key" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /></customHeaders> </httpProtocol> </system.webServer>
注意【Access-Control-Allow-Headers】屬性,里面表示iis允許接受的headers的集合,如果沒有key則不能在JQuery.ajax中使用beforeSend(或者headers:{"key":"11111"},)方法傳遞參數.如果在HTTP請求中會在請求頭里加入其它屬性,則一定要在
<add name="Access-Control-Allow-Headers" value="Origin,X-Requested-With,Content-Type,accept,key" />
中聲明。
2.在Global.asax文件中設置:
protected void Application_BeginRequest(object sender, EventArgs e) { var req = System.Web.HttpContext.Current.Request; if (req.HttpMethod == "OPTIONS")//過濾options請求,用於js跨域 { Response.StatusCode = 200; Response.SubStatusCode = 200; Response.End(); } }
用於過濾所有的OPTIONS請求
3.在B頁面中進行如下請求:
$.ajax({ type: "POST", contentType: "application/x-www-form-urlencoded", url: "http://api.xx.com/api/GetAllPeople", dataType: "json", data:{DM:52,key:"11111"}, success: function (result) { alert(JSON.stringify(result)); } });
總結:
遇到問題是需要冷靜,創建demo測試的時候demo需要干凈,最好全過程重新創建。
另:
1.據說在apicontroller上添加[EnableCors]屬性也可以進行跨域訪問,不過我沒找到,可參考下面文章:ASP.NET Web API自身對CORS的支持: EnableCorsAttribute特性背后的故事;
2.jsonp方式的請求只支持GET方式的請求,所以不能滿足現在的需要(帶參數的POST跨域請求);
