摘要:跨域概述兩個(gè)不同域互相請求,稱為跨域,是由瀏覽器同源策略限制的一類請求場景。同源策略限制以下幾種行為和無法讀取無法獲得請求不能發(fā)送目前主流的用于解決跨域問題的方法跨域缺點(diǎn)這種方法只適用于和窗口,和無法通過這種方法。
跨域概述
兩個(gè)不同域互相請求,稱為跨域,是由瀏覽器同源策略限制的一類請求場景。
--> 同源策略/SOP(Same origin policy)是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到CSFR等攻擊。所謂同源是指"協(xié)議+域名+端口"三者相同。
同源策略限制以下幾種行為:
1.) Cookie、LocalStorage 和 IndexDB 無法讀取
2.) DOM無法獲得
3.) AJAX 請求不能發(fā)送
目前主流的用于解決跨域問題的方法:
iframe跨域 document.domain+iframe缺點(diǎn):這種方法只適用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 無法通過這種方法。
實(shí)現(xiàn)原理:兩個(gè)頁面都通過js強(qiáng)制設(shè)置document.domain為基礎(chǔ)主域,就實(shí)現(xiàn)了同域。
1.)父窗口:(http://www.domain.com/a.html)
2.)子窗口:(http://child.domain.com/b.html)
-->iframe是什么?iframe 元素會(huì)創(chuàng)建包含另外一個(gè)文檔的內(nèi)聯(lián)框架(即行內(nèi)框架)
postMessage跨域postMessage是HTML5 XMLHttpRequest Level 2中的API,且是為數(shù)不多可以跨域操作的window屬性之一,它可用于解決以下方面的問題:
a.) 頁面和其打開的新窗口的數(shù)據(jù)傳遞
b.) 多窗口之間消息傳遞
c.) 頁面與嵌套的iframe消息傳遞
d.) 上面三個(gè)場景的跨域數(shù)據(jù)傳遞
用法:postMessage(data,origin)方法接受兩個(gè)參數(shù)
data: html5規(guī)范支持任意基本類型或可復(fù)制的對象,但部分瀏覽器只支持字符串,所以傳參時(shí)最好用JSON.stringify()序列化。
origin: 協(xié)議+主機(jī)+端口號,也可以設(shè)置為*,表示可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"。
1.)a.html:(http://www.domain1.com/a.html)
2.)b.html:(http://www.domain2.com/b.html)
window.name+iframewindow.name屬性的獨(dú)特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)。
1.)a.html:(http://www.domain1.com/a.html)
var proxy = function(url, callback) { var state = 0; var iframe = document.createElement("iframe"); // 加載跨域頁面 iframe.src = url; // onload事件會(huì)觸發(fā)2次,第1次加載跨域頁,并留存數(shù)據(jù)于window.name iframe.onload = function() { if (state === 1) { // 第2次onload(同域proxy頁)成功后,讀取同域window.name中數(shù)據(jù) callback(iframe.contentWindow.name); destoryFrame(); } else if (state === 0) { // 第1次onload(跨域頁)成功后,切換到同域代理頁面 iframe.contentWindow.location = "http://www.domain1.com/proxy.html"; state = 1; } }; document.body.appendChild(iframe); // 獲取數(shù)據(jù)以后銷毀這個(gè)iframe,釋放內(nèi)存;這也保證了安全(不被其他域frame js訪問) function destoryFrame() { iframe.contentWindow.document.write(""); iframe.contentWindow.close(); document.body.removeChild(iframe); } }; // 請求跨域b頁面數(shù)據(jù) proxy("http://www.domain2.com/b.html", function(data){ alert(data); });
2.)proxy.html:(http://www.domain1.com/proxy....
中間代理頁,與a.html同域,內(nèi)容為空即可。
3.)b.html:(http://www.domain2.com/b.html)
總結(jié):通過iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個(gè)就巧妙地繞過了瀏覽器的跨域訪問限制,但同時(shí)它又是安全操作。
AJAX跨域 Vue ProxyTable本質(zhì)是創(chuàng)建本地服務(wù)器,由本地服務(wù)器請求跨域服務(wù)器上的數(shù)據(jù),服務(wù)器之間沒有同源限制,
Access-Control-Allow-Origin參數(shù)設(shè)置在被請求的文件中添加一個(gè)header(IE10以下不支持)
jsonp方法缺點(diǎn):只能實(shí)現(xiàn)get一種請求。
優(yōu)點(diǎn):簡單適用,老式瀏覽器全部支持,服務(wù)器改造非常小。
原理:網(wǎng)頁通過添加一個(gè)元素,向服務(wù)器請求JSON數(shù)據(jù),這種做法不受同源政策限制;服務(wù)器收到請求后,將數(shù)據(jù)放在一個(gè)指定名字的回調(diào)函數(shù)里傳回來。
原生實(shí)現(xiàn)//js function addScriptTag(src) { var script = document.createElement("script"); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag("http://example.com/ip?callback=foo"); } function foo(data) { console.log("Your public IP address is: " + data.ip); }; //服務(wù)端JQuery方法
jquery會(huì)自動(dòng)生成一個(gè)全局函數(shù)來替換callback=?中的問號,之后獲取到數(shù)據(jù)后又會(huì)自動(dòng)銷毀,實(shí)際上就是起一個(gè)臨時(shí)代理函數(shù)的作用。
get$.get("http://example.com/data.php?callback",function(){ alert("123"); },"jsonp");getJson
getJSON方法會(huì)自動(dòng)判斷是否跨域,不跨域的話,就調(diào)用普通的ajax方法;跨域的話,則會(huì)以異步加載js文件的形式來調(diào)用jsonp的回調(diào)函數(shù)。
$.getJson("http://example.com/data.php?callback=?",function(){ alert("123"); });ajax包裹jsonp
以上做法還有一種解釋就是JQuery把jsonp的實(shí)現(xiàn)封裝在了ajax中
$.ajax({ type: "GET", url: "http://www.b.com/jsonp.js" dataType: "jsonp", jsonp:"callback",//“callback”:任意名字都可以 success: function(data) { //對data的處理 }, error: function(jqXHR){ alert("發(fā)生錯(cuò)誤:" + jqXHR.status); }, }); //服務(wù)端的修改 $jsonp = $_GET["callback"];//callback名字和請求的名字相同
-->ajax是什么?通過在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,AJAX 可以使網(wǎng)頁實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁的情況下,對網(wǎng)頁的某部分進(jìn)行更新。
vue實(shí)現(xiàn)jsonp//vue js this.$http.jsonp("http://www.domain2.com:8080/login", { params: {}, jsonp: "onBack" }).then((res) => { console.log(res); }) //node.js后端代碼 var querystring = require("querystring"); var http = require("http"); var server = http.createServer(); server.on("request", function(req, res) { var params = qs.parse(req.url.split("?")[1]); var fn = params.callback; // jsonp返回設(shè)置 res.writeHead(200, { "Content-Type": "text/javascript" }); res.write(fn + "(" + JSON.stringify(params) + ")"); res.end(); }); server.listen("8080"); console.log("Server is running at port 8080...");WebSocket協(xié)議跨域
WebSocket是HTML5新的一種通信協(xié)議,使用ws://(非加密)和wss://(加密)作為協(xié)議前綴。該協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過它進(jìn)行跨源通信。
下面是一個(gè)例子,瀏覽器發(fā)出的WebSocket請求的頭信息。
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
上面代碼中,有一個(gè)字段是Origin,表示該請求的請求源(origin),即發(fā)自哪個(gè)域名。正是因?yàn)橛辛薕rigin這個(gè)字段,所以WebSocket才沒有實(shí)行同源政策。因?yàn)榉?wù)器可以根據(jù)這個(gè)字段,判斷是否許可本次通信。如果該域名在白名單內(nèi),服務(wù)器就會(huì)做出如下回應(yīng)。
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chatCORS
CORS是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。它是W3C標(biāo)準(zhǔn),是跨源AJAX請求的根本解決方法。相比JSONP只能發(fā)GET請求,CORS允許任何類型的請求。IE瀏覽器不能低于IE10。
整個(gè)CORS通信過程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對于開發(fā)者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請求,但用戶不會(huì)有感覺。
因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。
簡單請求只要同時(shí)滿足以下兩大條件,就屬于簡單請求。
(1) 請求方法是以下三種方法之一:
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain
對于簡單請求,瀏覽器直接發(fā)出CORS請求。具體來說,就是在頭信息之中,增加一個(gè)Origin字段。
下面是一個(gè)例子,瀏覽器發(fā)現(xiàn)這次跨源AJAX請求是簡單請求,就自動(dòng)在頭信息之中,添加一個(gè)Origin字段。
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
如果Origin指定的源,不在許可范圍內(nèi),服務(wù)器會(huì)返回一個(gè)正常的HTTP回應(yīng)。如果Origin指定的域名在許可范圍內(nèi),服務(wù)器返回的響應(yīng),會(huì)多出幾個(gè)頭信息字段。
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8非簡單請求
非簡單請求是那種對服務(wù)器有特殊要求的請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡單請求的CORS請求,會(huì)在正式通信之前,增加一次HTTP查詢請求,稱為"預(yù)檢"請求(preflight)。"預(yù)檢"請求用的請求方法是OPTIONS,表示這個(gè)請求是用來詢問的。"預(yù)檢"請求的HTTP頭信息:
Origin: 請求域名 Access-Control-Request-Method: 請求自身的方法 Access-Control-Request-Headers: 自定義的頭部信息
發(fā)送請求后,服務(wù)器可以決定是否允許這種類型的請求,服務(wù)器通過在響應(yīng)中發(fā)送如下頭部與瀏覽器進(jìn)行溝通
Access-Control-Allow-Origin: 相同的源信息,可以是* Access-Control-Allow-Methods: 允許的方法 Access-Control-Allow-Headers: 允許的頭部 Access-Control-Max-Age:應(yīng)該講這個(gè)preflight緩存多久
preflight請求結(jié)束后,結(jié)果就按照響應(yīng)中指定的時(shí)間緩存起來,而為此付出的代價(jià)只是第一次發(fā)送請求的時(shí)候會(huì)多發(fā)送一次HTTP請求。
帶憑據(jù)的請求CORS請求默認(rèn)不發(fā)送Cookie和HTTP認(rèn)證信息。如果要把Cookie發(fā)到服務(wù)器,一方面要服務(wù)器同意,指定Access-Control-Allow-Credentials字段。
Access-Control-Allow-Credentials: true
另一方面,開發(fā)者必須在AJAX請求中打開withCredentials屬性。
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
前端XMLHttpRequest請求代碼
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDR兼容 xhr.withCredentials = true;// 前端設(shè)置是否帶cookie xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } }; xhr.open("post", "http://www.domain2.com:8080/login", true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.send();
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/93461.html
摘要:同源策略所謂同源是指協(xié)議,域名,端口均相同。同源策略是瀏覽器的一個(gè)安全功能,不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方資源。需注意的是由于同源策略的限制,所讀取的為跨域請求接口所在域的,而非當(dāng)前頁。 一、什么是跨域 1.URL解析 URL (Uniform Resource Locator )統(tǒng)一資源定位符(URL)是用于完整地描述Internet上網(wǎng)頁和其他資源的地址的...
摘要:關(guān)于咱們先了解在開發(fā)過程中的主要作用解決跨域負(fù)載均衡一解決跨域如果要理解什么是跨域廣義上的跨域是指一個(gè)域下的文檔或腳本試圖去請求另一個(gè)域下的資源。標(biāo)記為備份服務(wù)器。當(dāng)主服務(wù)器不可用時(shí),將傳遞與備份服務(wù)器的連接。 關(guān)于nginx,咱們先了解nginx在開發(fā)過程中的主要作用 nginx解決跨域 nginx負(fù)載均衡 一、nginx解決跨域 如果要理解什么是跨域 廣義上的跨域是指一個(gè)域下的...
摘要:實(shí)現(xiàn)跨域的原理通過方式請求載入并執(zhí)行一個(gè)文件,相當(dāng)于通過的形式的導(dǎo)入一個(gè)外部的方法語法該函數(shù)是簡寫的函數(shù),等價(jià)于在中,您可以通過使用形式的回調(diào)函數(shù)來加載其他網(wǎng)域的數(shù)據(jù),如。將自動(dòng)替換為正確的函數(shù)名,以執(zhí)行回調(diào)函數(shù)。 更多詳情見http://blog.zhangbing.club/Ja... 最近在項(xiàng)目開發(fā)的過程中遇到一些Javascript 跨域請求的問題,今天抽空對其進(jìn)行總結(jié)一下,以...
摘要:前言原文地址前端跨域總結(jié)博主博客地址的個(gè)人博客相信每一個(gè)前端對于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。通過跨域前面說過了,瀏覽器有一個(gè)同源策略,其限制之一是不能通過的方法去請求不同源中的文檔。 前言 原文地址:前端跨域總結(jié) 博主博客地址:Damonare的個(gè)人博客 相信每一個(gè)前端er對于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。但跨域方法的多種多樣實(shí)在讓人目...
摘要:前言原文地址前端跨域總結(jié)博主博客地址的個(gè)人博客相信每一個(gè)前端對于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。通過跨域前面說過了,瀏覽器有一個(gè)同源策略,其限制之一是不能通過的方法去請求不同源中的文檔。 前言 原文地址:前端跨域總結(jié) 博主博客地址:Damonare的個(gè)人博客 相信每一個(gè)前端er對于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。但跨域方法的多種多樣實(shí)在讓人目...
摘要:類似這樣而在客戶端我們只需要定義一個(gè)預(yù)定好的回調(diào)函數(shù)即可。處理跨域請求得到的數(shù)據(jù)其中的是我們在客戶端定義好的在數(shù)據(jù)請求成功后要執(zhí)行的回調(diào)函數(shù)。 跨域產(chǎn)生的原因 跨域是由瀏覽器的同源策略引起的,即不同源(協(xié)議,域名,端口中其中有一個(gè)不同)的js是不能讀取對方的資源的。當(dāng)要網(wǎng)站中的js要請求其他網(wǎng)站的數(shù)據(jù)時(shí)就會(huì)產(chǎn)生跨域問題,就像下面這樣,瀏覽器會(huì)報(bào)錯(cuò)。 showImg(https://se...
閱讀 2917·2021-10-27 14:19
閱讀 547·2021-10-18 13:29
閱讀 1143·2021-07-29 13:56
閱讀 3561·2019-08-30 13:19
閱讀 1937·2019-08-29 12:50
閱讀 1065·2019-08-23 18:16
閱讀 3532·2019-08-22 15:37
閱讀 1908·2019-08-22 15:37