跨域請求沒法處理的問題,因爲爲了阻止惡意的網站經過JS腳原本竊取正常網站受保護的資源。所由全部的瀏覽器的默認策略是阻止XmlHttpRequest的跨域的異步請求。 可是對於一個 複合型的應用集合來講,可能須要使用不一樣的域來部署咱們的應用。對於這種正常的需求,咱們的服務與應用就須要可以支持指定信認域的跨域的異步請法。web
一般來講,咱們有三種替代方案跨域
1, 使用JSONP,瀏覽器
JSONP(JSON with Padding), 但因爲JSONP使用的是在HTML DOM中加入<script>標籤來包裹來對提供GET的服務請求數據,全部JSONP只對HTTP GET方式的請求取做用。咱們的SOA框架,大可能是使用POST的請求。cors
2, 使用分離的「Proxy」代理服務,框架
代理服務是指,在同一個請求的域下建立一個代理的服務, Ajax請求這個代理服務,由代理服務來路由這個請求到目標域的服務上。 若是咱們的全部的運用都必須使用HTML頁面來實現。 那這種方式,須要爲每個不一樣域的應用建立代理服務。 但請注意,若是咱們的應用是門戶網,請求可能來自外面的人, 對於性能需求高,那麼使用HTML是不可行的。咱們須要使用ASP.NET MVC結構, 那麼Controller層就如同咱們的代理服務層。dom
3, 使用CORS異步
CORS,Cross-Origin Resource Sharing, 這是一種新的對跨域支持的方法, 它是經過定義一系列的HTTP Headers 在Service 與Client, 服務端能夠去掉對於跨域的約束,不只可使用GET,還可使用POST, PUT,或是DELETE, XmlHttpRequest對象已經實現了CORS, 將它做爲正常的AJAX調用。可是目前只有最新版本的瀏覽器才支持, 對於Firefox 3.5如下,Safari 4如下,Chrome 3如下, IE 10 如下,可使用XDomainRequest對象來代替XmlHttpRequest對象來實現。性能
瀏覽器對於使用CORS的請求,會分紅次請求,第一次,預先受權請求,會將請求的方式變成OPTIONS, 請求的數據爲空,這個過程其實是在看當前的Origin是否被服務容許,若是容許只服務返回200OK, 不然返回405 Method NOT Allowed, 第二次,正常請求,瀏覽器將請求的數據POST發送服務,服務端會正常響應。 注意下面是Chrome的,IE的話,只會顯示一條。網站
1, 應用, 對於應用層來講, 該怎麼樣寫,仍是怎麼樣寫,不須要變化。但對於底版本的瀏覽器的支持須要改代碼,不能使用XmlHttpRequest。須要使用XDomainRequest。spa
2, 服務, 這裏咱們使用的是WCF, 對於使用ASP.NET Web API的話,使用參考:https://msdn.microsoft.com/en-us/magazine/dn532203.aspx, 或是Google, CORS in ASP.NET Web Api.
對於WCF,我參考了 CarlosFigueira寫的 http://blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support-in-wcf.aspx ,文章寫的很是不錯, 可是我發現,其它它是一個半成品,沒有實現玩,它的目的是建立一個新的Operation,只是支持OPTIONS方式的請求,Action的名稱是當前操做的名稱 +特定的後綴。 但這樣問題來了,客戶端瀏覽器的請求,每一次不會自動加上這個後綴,全部Invoke一直都不會被調用。 你們的興趣下載了使用的話,若是想結合到本身的項目中, 可要記得把Web.config中的<modules runAllManagedModulesForAllRequests="true">去掉。 固然,前提是,你使用的Service都是本身經過ServiceHostFactory建立出來的, 若是使用默認的,是不會支持的。 其它 CarlosFigueira想法。 我作了一些改變。 實現步驟以下:
1,在IIS中,添加Http Response Header 3個,以下
建議這個設置在WebSite上, 這樣你的服務在這個Website下做爲一個Web Application的話,將自動繼承這些配置。 寫在web.config,能夠方便控制容許訪問的域。當前我使用 *, 這樣全部的域都能訪問,若是想指定哪些域的話,能夠改爲如 Http://domain1.com,Http://domain2......。那麼只有來自這些域的請求才能處理。固然這個設置,或以在WCF,添加本身的IDispatchMessageInspector實現, 在BeforeSendReply事件中,添加響應頭。
2,在使用自定ServiceHostFactory,建立服務時, 咱們能夠指定IServiceBehavior, 在它的ApplyDispatchBehavior事件中。 找到全部的Operation,對它注入WebInvokeAttribute, Method設置成*, 目的是動態將Operation對 Method=OPTIONS的請求處理, 以下代碼
foreach (ServiceEndpoint endpoint in desc.Endpoints)
{
foreach (var operation in endpoint.Contract.Operations)
{
//Add WebInvoke Attribute to all operation except for WebGet only, so that our opeations are able to handle OPTIONS Http Request Method for CORS issue.
if ( !operation.Behaviors.Any(d => d is WebGetAttribute)
&& !operation.Behaviors.Any(d => d is WebInvokeAttribute))
{
WebInvokeAttribute wia = new WebInvokeAttribute();
wia.UriTemplate = operation.Name;
wia.Method = "*";
operation.Behaviors.Add(wia);
}
}
}
3,當OPTIONS方式的請求來到時,在自定的 IOperationInvoker的invoke事件中, 判斷當前的Http Method是否爲OPTIONS, 若是是的話,不處理正常邏輯, 返回一個200 OK的響應。代碼以下
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
string operationName = "";
if (OperationContext.Current.IncomingMessageHeaders.Action != null)
{
operationName = OperationContext.Current.IncomingMessageHeaders.Action.ToString();
}
if (OperationContext.Current.IncomingMessageProperties.Keys.Contains("HttpOperationName"))
{
operationName = OperationContext.Current.IncomingMessageProperties["HttpOperationName"].ToString();
}
HttpRequestMessageProperty request = System.ServiceModel.OperationContext.Current.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty;
//If enable CORS, then we need to handle OPTIONS Method to reply OK, so that the browser will seed the right POST request.
if (request != null
&& request.Method == "OPTIONS" )
{
System.ServiceModel.Channels.Message input = (System.ServiceModel.Channels.Message)inputs[0];
outputs = null;
return HandlePreflight(input, operationName);
}
else
{
正常處理。。。。
}
}
System.ServiceModel.Channels.Message HandlePreflight(System.ServiceModel.Channels.Message input, string operationName)
{
System.ServiceModel.Channels.Message reply = System.ServiceModel.Channels.Message.CreateMessage(MessageVersion.None, operationName);
HttpResponseMessageProperty httpResponse = new HttpResponseMessageProperty();
reply.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
httpResponse.SuppressEntityBody = true;
httpResponse.StatusCode = System.Net.HttpStatusCode.OK;
httpResponse.Headers.Add(CorsConstants.AccessControlAllowOrigin, "*");
httpResponse.Headers.Add(CorsConstants.AccessControlAllowMethods, string.Join(",", new List<string>() { "POST", "GET", "OPTIONS" }));
return reply;
}
結束。