1. 程式人生 > >跨域的另一種解決方案——CORS(Cross-Origin Resource Sharing)跨域資源共享

跨域的另一種解決方案——CORS(Cross-Origin Resource Sharing)跨域資源共享

      在我們日常的專案開發時使用AJAX,傳統的Ajax請求只能獲取在同一個域名下面的資源,但是HTML5打破了這個限制,允許Ajax發起跨域的請求。瀏覽器是可以發起跨域請求的,比如你可以外鏈一個外域的圖片或者指令碼。但是Javascript指令碼是不能獲取這些資源的內容的,它只能被瀏覽器執行或渲染。主要原因還是出於安全考慮,瀏覽器會限制指令碼中發起的跨站請求。(同源策略, 即JavaScript或Cookie只能訪問同域下的內容)。跨域的解決方案有多重JSONP、Flash、Iframe等,當然還有CORS(跨域資源共享,Cross-Origin Resource Sharing)今天就來了解下CORS的原理,以及如何使用。

一、CORS概述

跨源資源共享標準通過新增一系列 HTTP 頭,讓伺服器能宣告那些來源可以通過瀏覽器訪問該伺服器上的各類資源(包括CSS、圖片、JavaScript 指令碼以及其它類資源)。另外,對那些會對伺服器資料造成破壞性影響的 HTTP 請求方法(特別是 GET 以外的 HTTP 方法,或者搭配某些MIME型別的POST請求),標準強烈要求瀏覽器必須先以 OPTIONS 請求方式傳送一個預請求(preflight request),從而獲知伺服器端對跨源請求所支援 HTTP 方法。在確認伺服器允許該跨源請求的情況下,以實際的 HTTP 請求方法傳送那個真正的請求。伺服器端也可以通知客戶端,是不是需要隨同請求一起傳送信用資訊(包括 Cookies 和 HTTP 認證相關資料)。

二、CORS原理

例如:域名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下的請求,那麼這個圖片就執行被載入。否則表示拒絕接受請求。

三、CORS跨域請求控制方法

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: 允許自定義的頭部,以逗號隔開,大小寫不敏感

四、瀏覽器支援情況

在大部分現代瀏覽器中有所支援,支援(部分支援)CORS協議的瀏覽器有IE8+, Firefox5+, Chrome12+, Safari4+,移動端幾乎全支援。

注:Internet Explorer 8 、9使用 XDomainRequest 物件實現CORS。

五、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="*"/>
CORS WebConfig 配置

 

            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 配置及啟用

如果不想使用全域性的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待補充。。。

七、如有不足,歡迎指出並補充。

轉載請註明出處,謝謝。

相關推薦

解決方案——CORSCross-Origin Resource Sharing資源共享

      在我們日常的專案開發時使用AJAX,傳統的Ajax請求只能獲取在同一個域名下面的資源,但是HTML5打破了這個限制,允許Ajax發起跨域的請求。瀏覽器是可以發起跨域請求的,比如你可以外鏈一個外域的圖片或者指令碼。但是Javascript指令碼是不能獲取這些資源的內容的,它只能被瀏覽器執行或渲染。主

Chrome瀏覽器開啟網頁慢的解決方案

目錄 前言 經驗總結 前言 折磨了我近一個月的Chrome開啟網頁慢的問題終於在今天告一段落,完結撒花~然後覺得很有必要發一篇文章來指引誤入歧途的後來人~ 網際網路上大部分教程無非都是教你在瀏覽器設定裡取消勾選一些選項,在區域網設定裡取消勾選云云,但還有一種情況

extjs grid 複製問題解決方案.

之前的專案中雖然也經常使用到extjs,但或許是沒有注意到,也或許是根本就沒有需要用到這個功能. 前幾天在和客戶討論需求時,客戶說想要能夠將gird表中的資料複製出來,當時沒多想,感覺這功能extjs應該是支援的,應該配置一個後幾個引數就能搞定的吧.可是回來後查extjs的

關於處理按鍵長按不用onKeyLongPress的解決方案

近期專案中需要處理按鍵長按事件,所以使用onKeyLongPress()進行了處理,但同時自己也發現了另一種處理長按的方式。首先來介紹一下使用onKeyLongPress()的相關方法。 一、onKeyLongPress使用 1.在onKeyDown()方法

請求的解決方案

<!doctype html> <html> <head> <meta charset="utf-8"> <title>無標題文件</title> </head> <script src="http://libs.

完全下單點登入的解決方案

  根據oums單點登入解決方案介紹 一文我們知道單點登入有兩種模型,一種是共同父域下的單點登入(例如域名都是 xx.a.com),還有就是完全跨域下的單點登入(例如域名是xx.a.com,xx.b.com),本文我們講一下完全跨域下的單點登入該怎麼實現。  

關於的5解決方案的知識

跨域 同源策略 首先從同源策略開始講 ----何謂同源:相同的域名、相同的協議、相同的埠即為同源,若有其一不同則視為不同域。 ----同源策略帶來的限制: 1.cookie、localstorage、indexDB無法讀取 2.DOM和JS物件無法讀取 3.AJAX請求無法傳送;

問題的根本解決方案CORS

介紹 關於跨域問題有很多的解決方案,這裡我們總結一下目前最通用最強大的解決方案:CORS。 W3C 的 Web 工作組推薦了一種新的機制,即跨域資源共享(Cross-origin Resource Sharing),簡稱CORS。其實這個機制就是實現了跨站訪問控制,

Web開發中的幾解決方案

隨著Web App的功能越來越強 各種跨域的需求催生了無數的跨域手法。甚至在HTML5標準中都給出了官方的跨域方法, 也是最近應付面試的需要,拿一篇文章來總結既有的各種跨域手段。 這些跨域通訊的方法大致可以分為兩類: 一類是Hack,比如通過title, navigation等物件傳遞資訊,JSONP可

訪問3解決方案

三種方法實現js跨域訪問 部落格分類: web前端 javascripthtmljsonp指令碼    javascript跨域訪問是web開發者經常遇到的問題,什麼是跨域,一個域上載入的指令碼獲取或操作另一個域上的文件屬性,下面將列出三種實現javascript跨域方法

React 流程圖的解決方案 GGEditor

要實現型別下圖的需求,所以研究了一些g6 editor   瞭解連結:https://antvis.github.io/g6/api/graph.html g6文件 https://www.yuque.com/antv/g6/api-graph g6 https://

微服務架構是解決方案

企業應用架構演變: 單機程式->c/s->b/s->面向服務架構(SOA)->微服務架構 加粗的是單體程式 微服務架構   細粒度SOA,是強調小型短暫元件的SOA,小即是美   重點是服務,如何進行服務之間解耦   每個服務元件都可以獨立開發、構建、測試、部署   自包含

華為ENSP中AR啟動失敗錯誤程式碼40,42,43,及啟動後一直#的問題的解決方案

系統是64位win10安裝ensp510時不斷40.42.43的錯且在不報錯時開啟ar時一直輸出#  查閱網上各種方法 一 一嘗試後發現, 我的問題是虛擬機器不是最新版本,且虛擬機器中沒有配置網絡卡,檢視是否有網絡卡配置,在virtualbox中點選左上角的管理,選擇全域性設定,然後在

Ubuntu18.04圖形介面崩潰無法進入桌面問題解決;cuda-9-0 (>= 9.0.176)的解決辦法

追加:【已解決,有一張顯示卡硬體不穩定】 參考我的最終記錄: 首先說明我的情況: Ubuntu18.04,配置了CUDA9.0,在執行一段時間後,圖形介面突然崩潰,當時正在使用Teamviewer遠端操作Matlab。 報錯主要是“starting nvidia

關於quartz定時任務實現Job介面無法註解為spring bean 的解決方案

  通常情況下,我們使用quartz之後,定時任務實現Job介面,並重寫execute()方法: public class QuartzJob1 implements Job { /** * quartz回撥此介面,此介面中為定時任務具體執行內容 *

內外網分離後如何保證檔案安全交換?介紹解決方案

近年來全球網路安全威脅態勢的加速嚴峻,使得企業對於網路安全有了前所未有的關注高度。 在嚴峻的安全態勢之下,企業的網路安全體系建設正從“以合規為導向”轉變到“以風險為導向”,從原來的“保護安全邊界”轉換到“保護核心資料資產”的思路上來。 絕大多數企業都在內部實施了內外網分離,網際網路與內網隔離,生產網與辦公

[JAVA IDEA]在使用maven專案中,無法讀取resources資料夾中的配置檔案的解決方案

1、在通過配置檔案來連線資料庫時,在resouces檔案中放入了db.properties配置檔案,但無法正常讀取到  讀取配置檔案資訊的程式碼: InputStream input=JdbcUtil.class.getClassLoader().getResourceAsStream("db.prope

有關於【該檔案的字元編碼需要在傳輸協議層宣告,或者在檔案中加入一個 BOM位元組順序標記】的解決辦法

昨天測試一個介面的時候發現一個異常,瀏覽器訪問一個controller,然後帶了一個JSON格式的引數,然後瀏覽器返回400錯誤,除錯發現下面的錯誤資訊: 純文字檔案的字元編碼未宣告。如果該檔案包含 US-ASCII 範圍之外的字元,該檔案將在某些瀏覽器配置中呈現為亂碼。該

關於win8下pip安裝mysql找不到config-win.h檔案的解決方案

關於win8下 pip安裝mysql報錯_mysql.c(42) : fatal error C1083: Cannot open include file: ‘config-win.h’: No such file or director的一種解決方案

關於IE7 IE8相容HTML5和CSS3的解決方案

 今天突然發現一網站用JS來實現這個支援 新增到head裡 <!--[if IE 7]> <script type='text/javascript' src='js/excanvas.js'></script> <link rel