日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

CORS简介

發(fā)布時(shí)間:2023/12/13 综合教程 35 生活家
生活随笔 收集整理的這篇文章主要介紹了 CORS简介 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  現(xiàn)在請(qǐng)跟我做:在您的瀏覽器的地址欄中輸入www.yhd.com并敲擊回車(chē)。在網(wǎng)站內(nèi)容全部加載完畢后,按F12打開(kāi)瀏覽器的調(diào)試窗口。當(dāng)切換到Sources頁(yè)時(shí),您會(huì)發(fā)現(xiàn)您當(dāng)前所看到的一號(hào)店的頁(yè)面是從多個(gè)不同的域中得到的:

  或許有些讀者會(huì)感到奇怪:在之前自己 寫(xiě)網(wǎng)頁(yè)的時(shí)候就曾經(jīng)嘗試訪(fǎng)問(wèn)非當(dāng)前域中的資源,卻怎么也不成功,一號(hào)店是如何做到的?

  當(dāng)然,這不是一號(hào)店的獨(dú)門(mén)絕技,而僅僅是使用了一些跨域訪(fǎng)問(wèn)的技術(shù)而已。而在本文中,我們就將對(duì)一種跨域訪(fǎng)問(wèn)技術(shù)CORS(Cross-Origin Resource Sharing)進(jìn)行介紹。

為什么要用CORS

  在需要做出一個(gè)技術(shù)決定時(shí),我們常常需要給出適當(dāng)?shù)睦碛伞>虲ORS而言,使用它的根本原因就是要完成資源的跨域訪(fǎng)問(wèn),也就是如何繞過(guò)Same-origin Policy。

  那么什么是Same-origin Policy呢?簡(jiǎn)單地說(shuō),在一個(gè)瀏覽器中訪(fǎng)問(wèn)的網(wǎng)站不能訪(fǎng)問(wèn)另一個(gè)網(wǎng)站中的數(shù)據(jù),除非這兩個(gè)網(wǎng)站具有相同的Origin,也即是擁有相同的協(xié)議、主機(jī)地址以及端口。一旦這三項(xiàng)數(shù)據(jù)中有一項(xiàng)不同,那么該資源就將被認(rèn)為是從不同的Origin得來(lái)的,進(jìn)而不被允許訪(fǎng)問(wèn)。

  但是這個(gè)限制的確過(guò)于嚴(yán)格了:一個(gè)大型網(wǎng)站常常擁有一系列子域。在這些域之間交換數(shù)據(jù)就會(huì)受到Same-origin Policy的限制。為了繞過(guò)該限制,業(yè)界提出了一系列解決該問(wèn)題的方法,例如更改document.domain屬性,跨文檔消息,JSONP以及CORS等。這些解決方案各有各的長(zhǎng)處,因此我們需要根據(jù)需求的不同來(lái)對(duì)這些方案進(jìn)行選擇。

  可以說(shuō)更改document.domain屬性的方法是最為直接快速的的方法,也較為常見(jiàn)。通過(guò)將從不同域中得到的腳本的document.domain屬性設(shè)置為同一個(gè)值,就可以使得這些腳本之間可以相互交互。例如從“http://blog.ambergarden.com”得到的網(wǎng)頁(yè)可以通過(guò)執(zhí)行如下的腳本改變其document.domain屬性中記錄的所屬域:

1 document.domain = ‘a(chǎn)mbergarden.com’;

  那么接下來(lái),該腳本就可以訪(fǎng)問(wèn)ambergarden.com中的數(shù)據(jù)了。

  這種方法也有其自身的劣勢(shì),那就是軟件開(kāi)發(fā)人員不可以隨便設(shè)置document.domain屬性的值,至少在一些瀏覽器上是如此的。

  跨文檔消息則是通過(guò)向Window實(shí)例發(fā)送消息來(lái)完成的。在使用時(shí),軟件開(kāi)發(fā)人員需要通過(guò)調(diào)用一個(gè)Window的postMessage()函數(shù)來(lái)向該Window實(shí)例發(fā)送消息。此時(shí)Window實(shí)例內(nèi)部的onmessage事件將被觸發(fā),進(jìn)而使得該事件的消息處理函數(shù)被調(diào)用。但是在接收到消息的時(shí)候,消息處理函數(shù)首先需要判斷消息來(lái)源的合法性,以避免惡意用戶(hù)通過(guò)發(fā)送消息的方式來(lái)非法執(zhí)行代碼。

  JSONP則是通過(guò)在文檔中嵌入一個(gè)<script>標(biāo)記來(lái)從另一個(gè)域中返回?cái)?shù)據(jù)。例如在頁(yè)面中添加一個(gè)如下的<script>標(biāo)記:

1 <script src="http://blog.ambergarden.com/someData?callback=some_func"/>

  該<script>標(biāo)記會(huì)向http://blog.ambergarden.com/someData發(fā)送一個(gè)GET請(qǐng)求。在數(shù)據(jù)返回到客戶(hù)端后,some_func()函數(shù)將會(huì)被調(diào)用。當(dāng)然,這種方法擁有一個(gè)顯著的缺點(diǎn),那就是只支持GET操作。

  就如您剛剛看到的一樣,上面所列出的各個(gè)方法各自有各自的缺點(diǎn)及局限性。而相較于這些方法,CORS則沒(méi)有那么多工作需要去做,也沒(méi)有那么多限制。因此在本文中,我們將主要對(duì)CORS進(jìn)行講解。

CORS運(yùn)行流程

  現(xiàn)在我們就來(lái)看一個(gè)通過(guò)CORS來(lái)進(jìn)行跨域訪(fǎng)問(wèn)的簡(jiǎn)單示例。假設(shè)ambergarden.com想從一個(gè)公有數(shù)據(jù)平臺(tái)public-data.com中返回一些數(shù)據(jù),那么在頁(yè)面邏輯中,其可以通過(guò)下面的代碼向public-data.com發(fā)送數(shù)據(jù)請(qǐng)求:

1 function retrieveData() {
2     var request = new XMLHttpRequest();
3     request.open('GET', 'http://public-data.com/someData', true);
4     request.onreadystatechange = handler;
5     request.send();
6 }

  在運(yùn)行這段代碼的之后,瀏覽器會(huì)向服務(wù)發(fā)送如下的請(qǐng)求:

1 GET /someData/ HTTP/1.1
2 Host: public-data.com
3 ......
4 Referer: http://ambergarden.com/somePage.html
5 Origin: http://ambergarden.com

  而一個(gè)支持CORS協(xié)議的服務(wù)可能會(huì)給出下面的響應(yīng):

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Content-Type: application/xml
4 ......
5 
6 [Payload Here]

  這里有一個(gè)值得注意的響應(yīng)頭:Access-Control-Allow-Origin。該響應(yīng)頭用來(lái)記錄可以訪(fǎng)問(wèn)該資源的域。在接收到服務(wù)端響應(yīng)后,瀏覽器將會(huì)查看響應(yīng)中是否包含Access-Control-Allow-Origin響應(yīng)頭。如果該響應(yīng)頭存在,那么瀏覽器會(huì)分析該響應(yīng)頭中所標(biāo)示的內(nèi)容。如果其包含了當(dāng)前頁(yè)面所在的域,那么瀏覽器就將知道這是一個(gè)被允許的跨域訪(fǎng)問(wèn),從而不再根據(jù)Same-origin Policy來(lái)限制用戶(hù)對(duì)該數(shù)據(jù)的訪(fǎng)問(wèn)。

  從整個(gè)訪(fǎng)問(wèn)數(shù)據(jù)的流程來(lái)看,用戶(hù)所使用的跨域訪(fǎng)問(wèn)數(shù)據(jù)的腳本實(shí)際上和普通的訪(fǎng)問(wèn)同一個(gè)域中數(shù)據(jù)的腳本并沒(méi)有什么不同。而不同的,僅僅是在響應(yīng)中多了一個(gè)Access-Control-Allow-Origin響應(yīng)頭。

  是不是很簡(jiǎn)單?實(shí)際上我們展示的僅僅是最為簡(jiǎn)單的Simple Request的執(zhí)行流程。而CORS則將導(dǎo)致跨域訪(fǎng)問(wèn)的請(qǐng)求分為三種:Simple Request,Preflighted Request以及Requests with Credential。

  如果一個(gè)請(qǐng)求沒(méi)有包含任何自定義請(qǐng)求頭,而且它所使用HTTP動(dòng)詞是GET,HEAD或POST之一,那么它就是一個(gè)Simple Request。但是在使用POST作為請(qǐng)求的動(dòng)詞時(shí),該請(qǐng)求的Content-Type需要是application/x-www-form-urlencoded,multipart/form-data或text/plain之一。

  如果一個(gè)請(qǐng)求包含了任何自定義請(qǐng)求頭,或者它所使用的HTTP動(dòng)詞是GET,HEAD或POST之外的任何一個(gè)動(dòng)詞,那么它就是一個(gè)Preflighted Request。如果POST請(qǐng)求的Content-Type并不是application/x-www-form-urlencoded,multipart/form-data或text/plain之一,那么其也是Preflighted Request。

  一般情況下,一個(gè)跨域請(qǐng)求不會(huì)包含當(dāng)前頁(yè)面的用戶(hù)憑證。一旦一個(gè)跨域請(qǐng)求包含了當(dāng)前頁(yè)面的用戶(hù)憑證,那么其就屬于Requests with Credential。

  前面我們已經(jīng)看過(guò)瀏覽器對(duì)Simple Request是如何進(jìn)行處理的。那么接下來(lái)我們就來(lái)看看Preflight Request是如何執(zhí)行的。相較于Simple Request,Preflight Request的運(yùn)行流程則略為復(fù)雜一些。

  假設(shè)現(xiàn)在我們要向公有數(shù)據(jù)平臺(tái)public-data.com寫(xiě)入一些數(shù)據(jù),那么我們就需要發(fā)送一個(gè)POST請(qǐng)求:

1 function sendData() {
2     var request = new XMLHttpRequest(),
3         payload = ......;
4     request.open('POST', 'http://public-data.com/someData', true);
5     request.setRequestHeader('X-CUSTOM-HEADER', 'custom_header_value');
6     request.onreadystatechange = handler;
7     request.send(payload);
8 }

  在執(zhí)行了該段代碼之后,瀏覽器首先發(fā)出的請(qǐng)求將如下所示:

1 OPTIONS /someData/ HTTP/1.1
2 Host: public-data.com
3 ......
4 Origin: http://ambergarden.com
5 Access-Control-Request-Method: POST
6 Access-Control-Request-Headers: X-CUSTOM-HEADER

  可以看到,我們首先發(fā)送的并不是POST請(qǐng)求,而是OPTION請(qǐng)求。該請(qǐng)求還通過(guò)Access-Control-Request-Method以及Access-Control-Request-Headers標(biāo)示了請(qǐng)求類(lèi)型以及請(qǐng)求中所包含的自定義HTTP Header。實(shí)際上,它相當(dāng)于向服務(wù)端詢(xún)問(wèn)訪(fǎng)問(wèn)資源的權(quán)限:“您好,我想向你這里發(fā)送數(shù)據(jù),你看可以嗎?”。而在真正訪(fǎng)問(wèn)資源前發(fā)送一個(gè)請(qǐng)求進(jìn)行探測(cè)也是該請(qǐng)求被稱(chēng)為是Preflight Request的原因。

  在服務(wù)端看到該OPTIONS請(qǐng)求后,其將分析該請(qǐng)求中的內(nèi)容并返回一個(gè)響應(yīng),以通知瀏覽器是否允許向它發(fā)送數(shù)據(jù):

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Access-Control-Allow-Methods: POST, GET, OPTIONS
4 Access-Control-Allow-Headers: X-CUSTOM_HEADER
5 Access-Control-Max-Age: 1728000
6 ......

  瀏覽器分析該響應(yīng)并了解到其被允許向服務(wù)端發(fā)送數(shù)據(jù)以后,其才會(huì)向服務(wù)端發(fā)送真正的POST請(qǐng)求:

1 POST /someData/ HTTP/1.1
2 Host: public-data.com
3 X-CUSTOM-HEADER: custom_header_value
4 ......
5 
6 [Payload Here]

  而服務(wù)端則會(huì)接收并處理該請(qǐng)求:

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Content-Type: application/xml
4 ......
5 
6 [Payload Here]

  最后一種請(qǐng)求Requests with Credential的運(yùn)行流程則和前兩種請(qǐng)求類(lèi)似。只不過(guò)在發(fā)送請(qǐng)求的時(shí)候,我們需要將用戶(hù)憑證包含在請(qǐng)求中:

1 function retrieveData() {
2     var request = new XMLHttpRequest();
3     request.open('GET', 'http://public-data.com/someData', true);
4     request.withCredentials = true;
5     request.onreadystatechange = handler;
6     request.send();
7 }

  而在服務(wù)端的響應(yīng)中,其將擁有一個(gè)額外的Access-Control-Allow-Credentials響應(yīng)頭:

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Content-Type: application/xml
4 ......
5 
6 [Payload Here]

集成對(duì)CORS的支持

  從上面的示例中已經(jīng)能夠看到,在使用CORS來(lái)訪(fǎng)問(wèn)數(shù)據(jù)的時(shí)候,客戶(hù)端不需要更改任何數(shù)據(jù)訪(fǎng)問(wèn)邏輯。所有的一切工作都是在服務(wù)端及瀏覽器之間自動(dòng)完成的。因此如果希望為一個(gè)系統(tǒng)集成CORS支持的時(shí)候,我們需要做的工作主要集中在服務(wù)端。

  當(dāng)然,集成工作實(shí)際上十分簡(jiǎn)單:在你的web.xml中添加一個(gè)Filter(或利用已有的Filter)并根據(jù)傳入的請(qǐng)求首先判斷其是哪一種CORS請(qǐng)求。在得知了請(qǐng)求的類(lèi)型后,我們就可以決定到底以哪種方式響應(yīng)用戶(hù)了。這里的邏輯較為簡(jiǎn)單,因此我就不再贅述了。

轉(zhuǎn)載請(qǐng)注明原文地址并標(biāo)明轉(zhuǎn)載:http://www.cnblogs.com/loveis715/p/4592246.html

總結(jié)

以上是生活随笔為你收集整理的CORS简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。