在咱們平常的項目開發時使用AJAX,傳統的Ajax請求只能獲取在同一個域名下面的資源,可是HTML5打破了這個限制,容許Ajax發起跨域的請求。瀏覽器是能夠發起跨域請求的,好比你能夠外鏈一個外域的圖片或者腳本。可是Javascript腳本是不能獲取這些資源的內容的,它只能被瀏覽器執行或渲染。主要緣由仍是出於安全考慮,瀏覽器會限制腳本中發起的跨站請求。(同源策略, 即JavaScript或Cookie只能訪問同域下的內容)。跨域的解決方案有多重JSONP、Flash、Iframe等,固然還有CORS(跨域資源共享,Cross-Origin Resource Sharing)今天就來了解下CORS的原理,以及如何使用。html
1、CORS概述web
跨源資源共享標準經過新增一系列 HTTP 頭,讓服務器能聲明那些來源能夠經過瀏覽器訪問該服務器上的各種資源(包括CSS、圖片、JavaScript 腳本以及其它類資源)。另外,對那些會對服務器數據形成破壞性影響的 HTTP 請求方法(特別是 GET 之外的 HTTP 方法,或者搭配某些MIME類型的POST請求),標準強烈要求瀏覽器必須先以 OPTIONS 請求方式發送一個預請求(preflight request),從而獲知服務器端對跨源請求所支持 HTTP 方法。在確認服務器容許該跨源請求的狀況下,以實際的 HTTP 請求方法發送那個真正的請求。服務器端也能夠通知客戶端,是否是須要隨同請求一塊兒發送信用信息(包括 Cookies 和 HTTP 認證相關數據)。ajax
2、CORS原理json
例如:域名A(http://a.example)的某 Web 應用程序中經過<img>標籤引入了域名B(http://b.foo)站點的某圖片資源(http://b.foo/image.jpg)。這就是一個跨域請求,請求http報頭包含Origin: http://a.example,若是返回的http報頭包含響應頭 Access-Control-Allow-Origin: http://a.example (或者Access-Control-Allow-Origin: http://a.example),表示域名B接受域名B下的請求,那麼這個圖片就運行被加載。不然表示拒絕接受請求。後端
3、CORS跨域請求控制方法api
1.http請求頭跨域
Origin: 普通的HTTP請求也會帶有,在CORS中專門做爲Origin信息供後端比對,代表來源域。瀏覽器
Access-Control-Request-Method: 接下來請求的方法,例如PUT, DELETE等等緩存
Access-Control-Request-Headers: 自定義的頭部,全部用setRequestHeader方法設置的頭部都將會以逗號隔開的形式包含在這個頭中安全
2.http響應頭
而後瀏覽器再根據服務器的返回值判斷是否發送非簡單請求。簡單請求前面講過是直接發送,只是多加一個origin字段代表跨域請求的來源。而後服務器處理完請求以後,會再返回結果中加上以下控制字段
Access-Control-Allow-Origin: 容許跨域訪問的域,能夠是一個域的列表,也能夠是通配符"*"。這裏要注意Origin規則只對域名有效,並不會對子目錄有效。即http://foo.example/subdir/ 是無效的。可是不一樣子域名須要分開設置,這裏的規則能夠參照同源策略
Access-Control-Allow-Credentials: 是否容許請求帶有驗證信息,XMLHttpRequest請求的withCredentials標誌設置爲true時,認證經過,瀏覽器纔將數據給腳本程序。
Access-Control-Expose-Headers: 容許腳本訪問的返回頭,請求成功後,腳本能夠在XMLHttpRequest中訪問這些頭的信息
Access-Control-Max-Age: 緩存這次請求的秒數。在這個時間範圍內,全部同類型的請求都將再也不發送預檢請求而是直接使用這次返回的頭做爲判斷依據,很是有用,大幅優化請求次數
Access-Control-Allow-Methods: 容許使用的請求方法,以逗號隔開
Access-Control-Allow-Headers: 容許自定義的頭部,以逗號隔開,大小寫不敏感
4、瀏覽器支持狀況
在大部分現代瀏覽器中有所支持,支持(部分支持)CORS協議的瀏覽器有IE8+, Firefox5+, Chrome12+, Safari4+,移動端幾乎全支持。
注:Internet Explorer 8 、9使用 XDomainRequest 對象實現CORS。
5、CORS使用案例
案例環境:客戶端使用jQuery,服務端WebApi(2.2)。因本人使用.net語言,因此服務端就使用webApi來演示了。
首先新建一個webApi項目,這裏就不截圖一步步介紹了,而後使用Nuget安裝支持cors的擴展組件,
Install-Package Microsoft.AspNet.WebApi.Cors
而後打開App_Start問價夾下的WebConfig.cs配置文件類,在Register方法中配置一個全局的cors,爲了方便我將一些參數配置到web.config配置文件中
<add key="cors_allowOrigins" value="*"/> <add key="cors_allowHeaders" value="*"/> <add key="cors_allowMethods" value="*"/>
var allowOrigins = ConfigurationManager.AppSettings["cors_allowOrigins"]; var allowHeaders = ConfigurationManager.AppSettings["cors_allowHeaders"]; var allowMethods = ConfigurationManager.AppSettings["cors_allowMethods"]; var globalCors = new EnableCorsAttribute(allowOrigins, allowHeaders, allowMethods); config.EnableCors(globalCors);
若是不想使用全局的CORS,能夠在某個方法或者ApiController上這樣配置:[EnableCors(origins: "*", headers: "*", methods: "*")],可使用具體的參數,多個參數以逗號分隔,不用說,確定英文逗號。origins 域名要帶上http的頂級域名。須要添加 using System.Web.Http.Cors;
通常請求來講,客戶端的AJAX請求不須要作任何改變,只須要服務端稍做改變便可。
客戶端js代碼: apiRootPath是我預先設置的api的頂級域名。
$.ajax({ url: apiRootPath + "api/Account/Register", type: "post", data: { "UserName": mobile, "Password": pwd }, dataType: "json", success: function (data) { if (data.State == true) { RegSuccess(mobile, pwd); } else { $("#errorText").html(data.Message); $("#registerBtn").text("註冊"); } } });
由於我配置了全局的CORS方法,並且服務端沒有特別之處了,和普通的網站(不跨越)寫法一致,這裏就不予貼出了。
若是須要對請求進行身份驗證,怎麼辦?咱們一cookies實現這個驗證。
$.ajax({ url: apiRootPath + "api/Account/Login", type: "post", data: { "UserName": userName, "Password": password }, crossDomain: true, xhrFields: { withCredentials: true }, dataType: "json", success: function (data) { if (data.State == true) { MLogin(userName, password); } else { $("#loginBtn").text("登陸"); $("#errorText").html(data.Message); } } });
注意這個兩句話:crossDomain: true,xhrFields: {withCredentials: true}
六:安全隱患
若是程序猿偷懶將Access-Control-Allow-Origin設置爲:Access-Control-Allow-Origin: * 容許任何來自任意域的跨域請求,那麼久存在被 DDoS攻擊的可能。
and待補充。。。
7、若有不足,歡迎指出並補充。
轉載請註明出處,謝謝。