一、跨域CORS是什么
當一個資源從與該資源本身所在的服務器的域或端口不同的域或不同的端口請求一個資源時,瀏覽器會發起一個跨域 HTTP 請求。出於安全考慮,瀏覽器會限制從腳本內發起的跨域HTTP請求或者攔截了服務器返回內容。例如,XMLHttpRequest 和 Fetch 遵循同源策略。因此,使用 XMLHttpRequest或 Fetch 的Web應用程序只能將HTTP請求發送到其自己的域;這種安全機制是為避免出現類似CSRF 跨站攻擊等問題。
二、實現CORS
根據CORS的定義和W3C相關規范,明白了跨域的關鍵問題是在於服務端是否允許;而服務端是通過W3C所規定的相關CORS heades來實現的;相關headers如下:
Access-Control-Allow-Origin:*
該字段是必須的。它的值要么是請求時Origin字段的值,要么是一個*,表示接受任意域名的請求。
Access-Control-Allow-Methods: POST, GET, OPTIONS
該字段可選。表明服務器允許客戶端使用 POST, GET 和 OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
該字段可選。表明服務器允許請求中攜帶字段 X-PINGOTHER 與 Content-Type。
Access-Control-Max-Age: 86400
表明該響應的有效時間為 86400 秒,也就是 24 小時。在有效時間內,瀏覽器無須為同一請求再次發起預檢請求。
Access-Control-Allow-Credentials: true
該字段可選。它的值是一個布爾值,表示是否允許發送Cookie。
三、WCF restful實現CORS
1.
View Code
View Code

1 /// <summary> 2 /// js跨域過濾器 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 5 public class CORSAttribute : Attribute, IServiceBehavior 6 { 7 public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) 8 { 9 } 10 /// <summary> 11 /// 擴展攔截 12 /// </summary> 13 /// <param name="serviceDescription"></param> 14 /// <param name="serviceHostBase"></param> 15 public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 16 { 17 foreach (ChannelDispatcher channelDispatch in serviceHostBase.ChannelDispatchers) 18 { 19 foreach (EndpointDispatcher endpointDispatch in channelDispatch.Endpoints) 20 { 21 endpointDispatch.DispatchRuntime.MessageInspectors.Add(new CrossDomain()); 22 } 23 } 24 } 25 26 public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 27 { 28 } 29 }
2.

1 /// <summary> 2 /// js跨域過濾器 3 /// </summary> 4 public class CrossDomain : IDispatchMessageInspector 5 { 6 #region IDispatchMessageInspector 7 /// <summary> 8 /// token驗證 9 /// </summary> 10 /// <param name="request"></param> 11 /// <param name="channel"></param> 12 /// <param name="instanceContext"></param> 13 /// <returns></returns> 14 public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 15 { 16 if (CrossDomain.DealOptions(ref request)) 17 { 18 return "3"; 19 } 20 return string.Empty; 21 } 22 23 /// <summary> 24 /// 回復內容 25 /// </summary> 26 /// <param name="reply"></param> 27 /// <param name="correlationState"></param> 28 public void BeforeSendReply(ref Message reply, object correlationState) 29 { 30 if ((string)correlationState == "3") 31 reply = MessageTempleHelper.GetDefault(JsonResultCode.SUCESS.ToString(), "OPTIONS"); 32 else 33 CrossDomain.DealtMessage(ref reply); 34 } 35 #endregion 36 37 38 /// <summary> 39 /// 對已處理的消息進行cross加工 40 /// </summary> 41 /// <param name="msg"></param> 42 public static void DealtMessage(ref Message msg) 43 { 44 try 45 { 46 var ct = ((HttpResponseMessageProperty)msg.Properties["httpResponse"]).Headers["Content-Type"]; 47 48 if (MimeTypes.Contains(ct)) 49 { 50 if (ct == MimeTypes[0]) 51 { 52 if (!msg.Properties.ContainsKey("WebBodyFormatMessageProperty")) 53 { 54 msg.Properties.Add("WebBodyFormatMessageProperty", new WebBodyFormatMessageProperty(WebContentFormat.Json)); 55 } 56 else if (msg.Properties["WebBodyFormatMessageProperty"] == new WebBodyFormatMessageProperty(WebContentFormat.Xml)) //強制將xml返回值改為json 57 { 58 msg.Properties.Remove("WebBodyFormatMessageProperty"); 59 msg.Properties.Add("WebBodyFormatMessageProperty", new WebBodyFormatMessageProperty(WebContentFormat.Json)); 60 } 61 } 62 var property = new HttpResponseMessageProperty(); 63 property.StatusCode = HttpStatusCode.OK; 64 property.Headers.Add("Content-Type", ct); 65 property.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 66 property.Headers.Add("Access-Control-Allow-Origin", "*"); 67 property.Headers.Add("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,Accept,imUserID,accessToken,appkey,userID,token"); 68 property.Headers.Add("Access-Control-Request-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 69 property.SuppressEntityBody = false; 70 property.SuppressPreamble = false; 71 if (msg.Properties.ContainsKey("httpResponse")) 72 msg.Properties.Remove("httpResponse"); 73 msg.Properties.Add("httpResponse", property); 74 } 75 } 76 catch (Exception ex) 77 { 78 Log4NetUtil.WriteErrLog("CrossDomain.DealtMessage", ex); 79 } 80 } 81 82 /// <summary> 83 /// 處理新的消息 84 /// </summary> 85 /// <param name="msg"></param> 86 public static void DealNewMessage(ref Message msg) 87 { 88 try 89 { 90 msg.Properties.Add("WebBodyFormatMessageProperty", new WebBodyFormatMessageProperty(WebContentFormat.Json)); 91 var property = new HttpResponseMessageProperty(); 92 property.StatusCode = HttpStatusCode.OK; 93 property.Headers.Add("Content-Type", MimeTypes[0]); 94 property.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 95 property.Headers.Add("Access-Control-Allow-Origin", "*"); 96 property.Headers.Add("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,Accept,imUserID,accessToken,appkey,userID,token"); 97 property.Headers.Add("Access-Control-Request-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 98 property.SuppressEntityBody = false; 99 property.SuppressPreamble = false; 100 if (msg.Properties.ContainsKey("httpResponse")) 101 msg.Properties.Remove("httpResponse"); 102 msg.Properties.Add("httpResponse", property); 103 } 104 catch { } 105 106 } 107 108 /// <summary> 109 /// 對當前請求是OPTIONS進行處理 110 /// </summary> 111 /// <param name="request"></param> 112 /// <returns>已處理為true,未處理為false</returns> 113 public static bool DealOptions(ref Message request) 114 { 115 try 116 { 117 if (((System.ServiceModel.Channels.HttpRequestMessageProperty)request.Properties["httpRequest"]).Method == "OPTIONS") 118 { 119 WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 120 WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*"); 121 WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,Accept,imUserID,accessToken,appkey,userID,token"); 122 WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Request-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 123 WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Accepted; 124 request.Close(); 125 return true; 126 } 127 } 128 catch { } 129 return false; 130 } 131 132 133 134 private static string[] _mimeTypes = null; 135 136 /// <summary> 137 /// html格式 138 /// </summary> 139 public static string[] MimeTypes 140 { 141 get 142 { 143 if (_mimeTypes == null) 144 { 145 _mimeTypes = new string[] { 146 "application/json; charset=utf-8", 147 "image/png" 148 }; 149 } 150 return _mimeTypes; 151 } 152 } 153 }
3.在所要公開的服務類上面[CORS],例如:

四、js測試
<script type="text/javascript"> $(function () { $("button").click(function () { var postData = JSON.stringify({ name: "ASDF.txt", md5Code: "F006096956B5062F8EFB72AF4DF59BC2"}); console.log(postData); $.ajax({ url: "http://127.0.0.1:16060/FileService/GetInfo", headers: { imUserID: "e82287ac45c14040ba8ef34b9c2dac29", accessToken: "U6wJgLoAdxVXUpx5R6AdZnFW/ytU+kgnVzaejZZoSdR31lNoRmDsQz42viOP7Jtm3iz8L2COA16r9rl5YUvZPhpHAAWxLNJBWWjHGKibHYejUuerO9qoxEkb6Yi+apPf60MzfmZ+SIgwhs6UBYOx2AbTkMdywYPCgKh8Q/mlVImUz0BU6WG4QCqgdqIefGi3" }, contentType: "application/json; charset=utf-8", type: "post", dataType: "json", data: postData, success: function (data) { $("#s").html(JSON.stringify(data)); console.log(data); }, error: function (e) { $("#e").html(e); console.log(e); } }); }); }); </script>
測試結果: