摘要:如果對你有幫助的話,歡迎一跨域首先我們在本地起一個服務(wù)器,用于接收客戶端的請求并作出回應(yīng)。五跨域原理域想和域通信,通過中間頁面。即借助接收到了發(fā)來的消息,并給予回應(yīng)跨域成功接下文跨域利用實踐前端各種跨域方式下
前言
常言道,"讀萬卷書,不如行萬里路"。技術(shù)的學(xué)習(xí)也是如此,唯有實踐才能更清楚的明白原理和加深印象,因此本文會利用node.js對前端的各種跨域方式進(jìn)行實踐,強(qiáng)烈建議一步一步跟著做,相信你肯定會對跨域有更深層次的理解。而由于篇幅限制,本文只會貼出關(guān)鍵性的代碼,本系列總共分為上下篇。具體的代碼請移步我的Github。如果對你有幫助的話,歡迎 star ヾ(′?ω?`)?
一、cors 跨域首先我們在本地起一個服務(wù)器,用于接收客戶端的請求并作出回應(yīng)。
//目錄:cors/server.js
const http = require("http"); http.createServer(function (req, res) { //設(shè)置響應(yīng)頭部 res.writeHead(200, {"Content-Type": "text/plain"}); res.write("This is a server page"); res.end(); }).listen(3333); console.log("server start!")
然后,開啟另一個服務(wù),服務(wù)里加載一個html頁面,頁面對發(fā)出xhr請求,模擬瀏覽器對服務(wù)器的請求。
//目錄:cors/clientServer.js
const express = require("express"); const app = express(); app.use(express.static("./public")); app.listen(3000) console.log("client server start");
//目錄:cors/public/client.html
const content = document.getElementById("content"); const xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.onload = function(){ if(xhr.readyState == 4) { if(xhr.status >= 200 && xhr.status <300 || xhr.status == 304) { content.innerHTML = "Reuqest was success:" + xhr.responseText; console.log("Request was success:", xhr.responseText); }else { content.innerHTML = "Reuqest was failed:" + xhr.status; console.log("Request was failed:", xhr.status); } } } // xhr.open("get", "http://localhost:3000/client.html", true); //不跨域 xhr.open("get", "http://localhost:3333", true); //跨域 xhr.send();
分別運(yùn)行兩個服務(wù),測試3000和3333接口,發(fā)現(xiàn)只有跨域的時候,請求的頭部才會帶著origin字段。此時我們修改cors/server.js, 加上這行代碼:
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
這行代碼代表服務(wù)器允許接收來自3000接口的請求,此時客戶端再次請求服務(wù)器,就能在用戶毫無感知的情況下完成跨域。
而此時如果想讓客戶端帶cookie請求呢?那么需要做以下工作:
1.cors/server.js 加上這行
res.setHeader("Access-Control-Allow-Credentials", true);
2.cors/public/client.html 加上這行
xhr.withCredentials = true;
然后,你就會發(fā)現(xiàn),客戶端會把當(dāng)前域下的cookie一起發(fā)給服務(wù)器啦╮( ̄▽ ̄")╭
ps:注意cookie只能細(xì)分到域名下,不能細(xì)分到端口。即沒辦法設(shè)置一個cookie僅在localhost:xxxx下。盡管端口不同會被瀏覽器認(rèn)為不同源。二、jsonp跨域
通常為了減輕web服務(wù)器的負(fù)載,我們把js、css,img等靜態(tài)資源分離到另一臺獨立域名的服務(wù)器上,在html頁面中再通過相應(yīng)的標(biāo)簽從不同域名下加載靜態(tài)資源,而被瀏覽器允許,基于此原理,我們可以通過動態(tài)創(chuàng)建script,再請求一個帶參網(wǎng)址實現(xiàn)跨域通信。
下面這個例子采用jQuery中的ajax方法,與服務(wù)器端約定將數(shù)據(jù)回傳到回調(diào)函數(shù)中,比如本例中的callback=person,然后我們就可以從回調(diào)函數(shù)person里獲取服務(wù)器傳給瀏覽器的數(shù)據(jù)了。另外,jsonp的缺點就是只能采用get請求。
1.目錄:jsonp/server.js
const http = require("http"); const urllib = require("url"); const httpdispatcher = require("httpdispatcher"); const dispatcher = new httpdispatcher(); const PORT = 1112; function handleRequest(req, res) { try { console.log(req.url); dispatcher.dispatch(req, res); }catch(err) { console.log(err); } } const server = http.createServer(handleRequest); dispatcher.onGet("/getPerson", function (req, res, next) { const data = {"name": "Jchermy", "company": "dog company"}; const params = urllib.parse(req.url, true); if(params.query && params.query.callback) { let str = `${params.query.callback}(${JSON.stringify(data)})`; res.write(str); res.end(); }else { res.write(JSON.stringify(data)); res.end(); } }) server.listen(PORT, function () { console.log("server listening on http://localhost: %s", PORT); })
2.目錄:jsonp/client.js
const express = require("express"); const app = express(); app.use(express.static("./public")); app.listen(1111); console.log("client start");
3.目錄:jsonp/public/index.html
index 姓名:
公司:
分別運(yùn)行客戶端和服務(wù)端,點擊“獲取跨域數(shù)據(jù)的按鈕”,當(dāng)前頁面(1111端口)就可以拿到1112端口的數(shù)據(jù)啦~~(●′ω`●)
三、document.domain + frame 跨域此方案僅限主域相同,子域不同的跨域應(yīng)用場景。
實現(xiàn)原理:兩個頁面都通過js強(qiáng)制設(shè)置document.domain為基礎(chǔ)主域,就實現(xiàn)了同域。
下面只是舉個例子幫助大家理解一下。
現(xiàn)在有兩個網(wǎng)址。百度知道和百度百科
https://zhidao.baidu.com/ https://baike.baidu.com/
在百度知道的網(wǎng)頁,寫下以下命令:
document.domain = "baidu.com"; const child= window.open("https://baike.baidu.com/");
在打開的百度百科的網(wǎng)頁,寫下以下命令:
document.domain = "baidu.com";
然后回到百度知道的網(wǎng)頁,就可以獲取到百度百科(子頁面)的元素啦:
const button = other.document.getElementById("search"); //四、window.name+iframe 跨域
window.name屬性的獨特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)。
在本地起兩個node服務(wù),分別占用3333和4444。父頁面是:
1.window-name/public/index.html
const proxy = function(url ,callback) { let status = 0; const iframe = document.createElement("iframe"); iframe.src = url; iframe.onload = function(){ if(status === 1) { callback(iframe.contentWindow.name); destoryFrame(); } else if (status === 0) { iframe.contentWindow.location = "http://localhost:4444/proxy.html"; status = 1; } } document.body.appendChild(iframe); }; function destoryFrame() { iframe.contentWindow.document.write(""); iframe.contentWindow.close(); document.body.removeChild(iframe); } proxy("http://localhost:3333/iframe.html", function(data) { alert(data); })
2.iframe 頁面是
window-name/public/iframe.html
3.還有一個代理頁面,跟父頁面同源。內(nèi)容為空就好。目錄:/window-name/public/proxy.html
總結(jié):通過iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制,但同時它又是安全操作。
五、location.hash+iframe 跨域原理:A域想和B域通信,通過中間頁面c。不同域之間通過location.hash來通信,而相同域之間直接通過js來通信。
實現(xiàn):A域:a.html ----> B域:b.html ----> A域:c.html,a與b不同域只能通過hash值單向通信,b與c也不同域也只能單向通信,但c與a同域,所以c可通過parent.parent訪問a頁面所有對象。
目錄:location-hash/public/a.html
a
目錄:location-hash/public/b.html
b
目錄:location-hash/public/c.html
然后,我們通過node服務(wù)將a.html和c.html部署在同一個端口下,將b.html部署在另一個端口。
//location-hash/server1.js app.use("/a.html", express.static(__dirname+"/public/a.html")); app.use("/c.html", express.static(__dirname+"/public/c.html")); app.listen(3333); //location-hash/server2.js app.use("/b.html", express.static(__dirname+"/public/b.html")); app.listen(4444);
最后,我們分別將兩個服務(wù)跑起來。訪問localhost:3333可以看到彈窗。
即b.html借助c.html接收到了a.html發(fā)來的消息,并給予回應(yīng)"hello admin",跨域成功~
接下文--->「跨域」利用node.js實踐前端各種跨域方式(下)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/95428.html
摘要:如果對你有幫助的話,歡迎一跨域首先我們在本地起一個服務(wù)器,用于接收客戶端的請求并作出回應(yīng)。五跨域原理域想和域通信,通過中間頁面。即借助接收到了發(fā)來的消息,并給予回應(yīng)跨域成功接下文跨域利用實踐前端各種跨域方式下 前言 常言道,讀萬卷書,不如行萬里路。技術(shù)的學(xué)習(xí)也是如此,唯有實踐才能更清楚的明白原理和加深印象,因此本文會利用node.js對前端的各種跨域方式進(jìn)行實踐,強(qiáng)烈建議一步一步跟著做...
摘要:技術(shù)的學(xué)習(xí)也是如此唯有實踐才能更清楚的明白原理和加深印象,因此本文會利用對前端的各種跨域方式進(jìn)行實踐,強(qiáng)烈建議一步一步跟著做,相信你肯定會對跨域有更深層次的理解。 前言 常言道,讀萬卷書,不如行萬里路。技術(shù)的學(xué)習(xí)也是如此,唯有實踐才能更清楚的明白原理和加深印象,因此本文會利用node.js對前端的各種跨域方式進(jìn)行實踐,強(qiáng)烈建議一步一步跟著做,相信你肯定會對跨域有更深層次的理解。而由于篇...
摘要:希望幫助更多的前端愛好者學(xué)習(xí)。前端開發(fā)者指南作者科迪林黎,由前端大師傾情贊助。翻譯最佳實踐譯者張捷滬江前端開發(fā)工程師當(dāng)你問起有關(guān)與時,老司機(jī)們首先就會告訴你其實是個沒有網(wǎng)絡(luò)請求功能的庫。 前端基礎(chǔ)面試題(JS部分) 前端基礎(chǔ)面試題(JS部分) 學(xué)習(xí) React.js 比你想象的要簡單 原文地址:Learning React.js is easier than you think 原文作...
摘要:用函數(shù)式編程對進(jìn)行斷舍離當(dāng)從業(yè)的老司機(jī)學(xué)會函數(shù)式編程時,他扔掉了的特性,也不用面向?qū)ο罅?,最后發(fā)現(xiàn)了真愛啊作用域和閉包作用域和閉包在里非常重要。旨在幫助非函數(shù)式編程的同學(xué),能快速切入到函數(shù)式編程的理念。 1、用函數(shù)式編程對JavaScript進(jìn)行斷舍離 當(dāng)從業(yè)20的JavaScript老司機(jī)學(xué)會函數(shù)式編程時,他扔掉了90%的特性,也不用面向?qū)ο罅?,最后發(fā)現(xiàn)了真愛啊!??! https:/...
摘要:用函數(shù)式編程對進(jìn)行斷舍離當(dāng)從業(yè)的老司機(jī)學(xué)會函數(shù)式編程時,他扔掉了的特性,也不用面向?qū)ο罅耍詈蟀l(fā)現(xiàn)了真愛啊作用域和閉包作用域和閉包在里非常重要。旨在幫助非函數(shù)式編程的同學(xué),能快速切入到函數(shù)式編程的理念。 1、用函數(shù)式編程對JavaScript進(jìn)行斷舍離 當(dāng)從業(yè)20的JavaScript老司機(jī)學(xué)會函數(shù)式編程時,他扔掉了90%的特性,也不用面向?qū)ο罅耍詈蟀l(fā)現(xiàn)了真愛啊!??! https:/...
閱讀 1211·2023-04-26 02:20
閱讀 3337·2021-11-22 14:45
閱讀 4111·2021-11-17 09:33
閱讀 971·2021-09-06 15:00
閱讀 1479·2021-09-03 10:30
閱讀 3837·2021-07-26 22:01
閱讀 990·2019-08-30 15:54
閱讀 530·2019-08-30 15:43