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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Web学习之跨域问题及解决方案

發(fā)布時(shí)間:2023/12/15 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Web学习之跨域问题及解决方案 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Web學(xué)習(xí)之跨域問題及解決方案

javascript/jquery

瀏覽數(shù):161

2017-5-8

在做前端開發(fā)時(shí),我們時(shí)常使用ajax與服務(wù)器通信獲取資源,享受ajax便利的同時(shí),也知道它有限制:跨域安全限制,即同源策略。

同源策略(SOP),核心是確保不同源提供的文件之間是相互獨(dú)立的
默認(rèn)情況下,XHR對(duì)象只能訪問與包含它的頁(yè)面處于同一域中的資源,這種限制可以預(yù)防某些惡意攻擊,但同時(shí)也帶來(lái)很多不便。

本篇對(duì)于常見的解決瀏覽器跨域問題的方案進(jìn)行總結(jié)闡述。

常見解決跨域問題的方案

在web開方中,解決跨域問題最常見的方法有:

  • document.domain+iframe(子域名代理)
  • jsonp實(shí)現(xiàn)跨域
  • CORS跨域資源共享
  • postMessage實(shí)現(xiàn)跨域

接下來(lái)對(duì)以上常用方式進(jìn)行詳細(xì)闡述:

document.domain + iframe(子域名代理)

對(duì)于主域相同而子域不同的情況,可以通過設(shè)置document.domain的辦法來(lái)解決。如:對(duì)于兩個(gè)文件http://www.a.com/a.html和http://blog.a.com/b.html均加上設(shè)置document.domain = ‘a(chǎn).com’;然后在a.html文件中創(chuàng)建一個(gè)iframe,通過iframe兩個(gè)js文件即可交互數(shù)據(jù):

//www.a.com/a.html ????<script> ????????document.doamin = 'a.com'; ????????var iframe = document.createElement('iframe'); ????????iframe.src = 'http://blog.a.com/b.html'; ????????document.body.appendChild(iframe); ????????iframe.onload = function() { ????????????var doc = iframe.contentDocument || iframe.contentWindow.document; ????????????// 在這里操縱b.html ????????????console.log(doc); ????????}; ????</script>

在blog.a.com/b.html內(nèi)編寫代碼:

//blog.a.com/b.html ????<script> ????????document.domain = 'a.com'; ????</script>

備注:某一頁(yè)面的domain默認(rèn)等于window.location.hostname。主域名是不帶www的域名,例如a.com,主域名前
面帶前綴的通常都為二級(jí)域名或多級(jí)域名,例如blog.a.com其實(shí)是二級(jí)域名。 domain只能設(shè)置為主域名,不可以在
blog.a.com中將domain設(shè)置為test.a.com。

問題:
1、安全性,當(dāng)一個(gè)站點(diǎn)(b.a.com)被攻擊后,另一個(gè)站點(diǎn)(c.a.com)會(huì)引起安全漏洞。
2、如果一個(gè)頁(yè)面中引入多個(gè)iframe,要想能夠操作所有iframe,必須都得設(shè)置相同domain。

jsonp實(shí)現(xiàn)跨域

JSONP,即帶填充的JSON,可以在JavaScript中繞過同源策略,發(fā)起跨域HTTP請(qǐng)求。
JSONP,一個(gè)無(wú)關(guān)標(biāo)準(zhǔn),使用腳本標(biāo)簽來(lái)跨域獲取數(shù)據(jù)的技術(shù)。
同源策略有一個(gè)顯著例外:HTML腳本元素是可以規(guī)避SOP檢查的。這意味著我們可以通過加載外部JavaScript文件的方式來(lái)向其他源發(fā)出HTTP請(qǐng)求。

<script>http://blog-resource.bj.bcebos.com/files/2016/03/info.js</script>
//http://blog-resource.bj.bcebos.com/files/2016/03/info.js ???var jsonpData = { ???????name: 'jsonp', ???????title: 'JSONP data' ???};

動(dòng)態(tài)的回調(diào)函數(shù)

JSONP通過script元素加載JSON,通過腳本URL的查詢字符串,服務(wù)器將響應(yīng)封裝在回調(diào)函數(shù)中,而回調(diào)函數(shù)名由請(qǐng)求者在URL查詢字符串中給出,此回調(diào)函數(shù),即填充。填充可以是任何有效的JavaScript表達(dá)式,最常見的是變量和回調(diào)函數(shù)。

<script> ????????var jsonpCallback = function(data) { ????????????console.log('The response data: ' + JSON.stringify(data)); ????????}; ????????var script = document.createElement('script'); ????????script.async = true; ????????script.src = 'http://blog-resource.bj.bcebos.com/files/2016/03/info2.js?callback=jsonpCallback'; ????????document.body.appendChild(script); ????</script>

在全局作用域下定義回調(diào)函數(shù),當(dāng)HTML DOM中加入script標(biāo)簽時(shí)發(fā)起請(qǐng)求,服務(wù)端可以通過URL獲取回調(diào)函數(shù)名,并生成返回如下類似內(nèi)容:

jsonpCallback({ ???????name: 'jsonp', ???????title: 'JSONP data' ???});

如php實(shí)現(xiàn):

<!--?php ??????header("Content-type: application/javascript"); ??????$callback = $_GET['callback']; ??????$data = json_encode(array( ??????????'name' =--> 'jsonp, ??????????'title' => 'JSONP data' ??????), JSON_PRETTY_PRINT); ??????echo "$callback($data);"; ???>

jQuery利用jsonp發(fā)送跨域請(qǐng)求:

$.ajax({??? ??????????url: '',? // 跨域URL?? ??????????type: 'GET',??? ??????????dataType: 'jsonp',??? ??????????jsonp: 'jsonpcallback', //默認(rèn)callback?? ??????????data: mydata, //請(qǐng)求數(shù)據(jù)?? ??????????timeout: 5000, ??????????success: function (json) { //客戶端jquery預(yù)先定義好的callback函數(shù),成功獲取跨域服務(wù)器上的 ???json數(shù)據(jù)后,會(huì)動(dòng)態(tài)執(zhí)行這個(gè)callback函數(shù)??? ??????????????if(json.actionErrors.length!=0){??? ??????????????????alert(json.actionErrors);??? ??????????????}??? ??????????},??? ??????????complete: function(XMLHttpRequest, textStatus){??? ??????????} ??????});

JSONP可以說(shuō)是最簡(jiǎn)單的解決跨域請(qǐng)求的方案,但JSONP只支持GET請(qǐng)求,且所能攜帶信息量有限,對(duì)于需要使用POST等請(qǐng)求方法或數(shù)據(jù)量比較大的時(shí)候就不適合使用JSONP。

跨域資源共享(CORS)

跨域資源共享(CORS)定義了瀏覽器和服務(wù)器如何通過可控方式進(jìn)行跨域通信。CORS通過添加特殊HTTP頭信息以允許瀏覽器和服務(wù)器判斷請(qǐng)求是成功還是失敗。幾乎所有現(xiàn)代瀏覽器都支持CORS。

HTTP請(qǐng)求
當(dāng)跨域發(fā)送HTTP請(qǐng)求時(shí),支持CORS的瀏覽器會(huì)通過,添加額外Origin頭信息指定請(qǐng)求源,其值包括請(qǐng)求協(xié)議、域名、端口。如:

Origin: http://www.codingplayboy.com

若請(qǐng)求頭中無(wú)Origin信息,服務(wù)器將不返回任何CORS頭信息。

服務(wù)端接收到請(qǐng)求時(shí)會(huì)檢查頭信息確定是否接受請(qǐng)求:若接受請(qǐng) 求,必須返回一個(gè)包含Access-Control-Allow-Origin響應(yīng)頭,其值與請(qǐng)求頭Origin值相同,如:

Access-Control-Allow-Origin: http://www.codingplayboy.com

對(duì)于公共資源且允許任何源請(qǐng)求數(shù)據(jù),服務(wù)器通常返回該值為通配符*,如:

Access-Control-Allow-Origin: *

瀏覽器接收到服務(wù)器HTTP響應(yīng)時(shí),首先會(huì)檢查Access-Control-Allow-Origin的值,只有當(dāng)值存在且同Origin匹配,才繼續(xù)處理該請(qǐng)求。

下面是一段使用CORS跨域請(qǐng)求的代碼:

function createCORS(url, method) { ????if (typeof XMLHttpRequest === 'undefined') { ????????return null; ????} ????//標(biāo)準(zhǔn)瀏覽器 ????var xhr = new XMLHttpRequest(); ????if ('withCredentials' in xhr) { ????????xhr.open(method, url, true); ????}else if (typeof XDomainRequest !== 'undefined') { ????????//IE ????????xhr = new XDomainRequest(); ????????xhr.open(method, null); ????}else { ????????//不支持CORS ????????xhr = null; ????} ????return xhr; } var req = createCORS('http://blog.codingplayboy.com', 'GET'); if (req) { ????req.onload = function() { ????}; ????req.send(); }

Cookie及HTTP認(rèn)證頭
我們還需要知道不同于普通的HTTP請(qǐng)求,使用CORS發(fā)送請(qǐng)求時(shí),默認(rèn)情況下,瀏覽器不會(huì)攜帶任何Cookie和HTTP認(rèn)證頭等識(shí)別信息,只有當(dāng)我們將XMLHttpRequest對(duì)象的withCredentials屬性值設(shè)為true,才在該請(qǐng)求發(fā)送時(shí)添加額外識(shí)別信息。

var xhr = new XMLHttpRequest(); xhr.withCredentials = true;

若服務(wù)器需要識(shí)別信息,則在響應(yīng)頭中添加Access-Control-Allow-Credentials響應(yīng)頭:

Access-Control-Allow-Credentials: true

若發(fā)送請(qǐng)求時(shí)將withCredentials設(shè)為true,服務(wù)端沒有返回該響應(yīng)頭,瀏覽器將拒絕該響應(yīng)。

本來(lái)一切都是美好的,然而XDomainRequest不支持withCredentials屬性,于是IE8、IE9并不支持請(qǐng)求時(shí)包含識(shí)別信息。

預(yù)檢請(qǐng)求
使用CORS時(shí),若請(qǐng)求方法不是GET,POST或HEAD,又或者使用了自定義HTTP頭,瀏覽器將發(fā)起預(yù)檢請(qǐng)求。

預(yù)檢請(qǐng)求是一個(gè)服務(wù)端認(rèn)證機(jī)制,在執(zhí)行請(qǐng)求之前會(huì)判斷該請(qǐng)求是否合法。
發(fā)送復(fù)雜請(qǐng)求時(shí),瀏覽器會(huì)將原始請(qǐng)求的方法和請(qǐng)求頭作為預(yù)檢請(qǐng)求的信息發(fā)送給服務(wù)器;服務(wù)器需要決定是否接受該請(qǐng)求并響應(yīng),預(yù)檢請(qǐng)求通常是使用一種OPTIONS的HTTP方法。

客戶端發(fā)起復(fù)雜請(qǐng)求時(shí),會(huì)先發(fā)起預(yù)檢,攜帶以下頭信息:

請(qǐng)求頭 描述
Origin 請(qǐng)求源
Access-Control-Request-Method 請(qǐng)求方法(HTTP方法)
Access-Control-Request-Headers 請(qǐng)求自定義頭(以逗號(hào)分隔)

服務(wù)器返回的響應(yīng)頭:

響應(yīng)頭 描述
Access-Control-Allow-Origin 允許的請(qǐng)求源(與請(qǐng)求頭Origin匹配)
Access-Control-Allow-Methods 允許的請(qǐng)求方法(以逗號(hào)分隔)
Access-Control-Allow-Headers 允許的頭信息(以逗號(hào)分隔)
Access-Control-Max-Age 預(yù)檢請(qǐng)求的緩存時(shí)間(單位:秒)
Access-Control-Allow-Credentials 指定請(qǐng)求是否支持認(rèn)證信息(可選)

客戶端接收到服務(wù)端的響應(yīng)后,會(huì)使用之前聲明的HTTP方法和請(qǐng)求頭發(fā)送真正的請(qǐng)求。

預(yù)檢請(qǐng)求會(huì)被瀏覽器緩存,緩存時(shí)間為Access-Control-Max-Age值,緩存時(shí)間內(nèi),后續(xù)相同類型的請(qǐng)求不再發(fā)起重復(fù)的預(yù)檢請(qǐng)求。IE8、IE9均不支持預(yù)檢請(qǐng)求。

HTML5 postMessage

HTML5的window.postMessage為瀏覽器帶來(lái)了一個(gè)安全的、基于事件的消息API。與之前的子域名代理通過iframe跨子域通信不同,使用postMessage不再是直接訪問一個(gè)文檔的屬性和方法,而是向文檔發(fā)送消息然后等待響應(yīng),這要求形成一條雙向的通信通道。

原文鏈接:http://blog.codingplayboy.com/2016/03/05/web_cross_origin/

總結(jié)

以上是生活随笔為你收集整理的Web学习之跨域问题及解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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