這篇文章主要為大家展示了“WEB前端跨域的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“WEB前端跨域的示例分析”這篇文章吧。
創(chuàng)新互聯(lián)2013年開創(chuàng)至今,先為萬全等服務建站,萬全等地企業(yè),進行企業(yè)商務咨詢服務。為萬全企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務解決您的所有建站問題。
WEB前端跨域解決方案
廣義的定義:跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源。
1、資源跳轉(zhuǎn): 鏈接、重定向、表單提交
2、資源嵌入:<link>
、<script>
、<img/>
、<frame>
等dom
標簽,還有樣式中background:url()
、@font-face()
等文件外鏈
3、腳本請求:js
發(fā)起的ajax
請求、dom
和js
對象的跨域操作等
同源策略/SOP(Same origin policy)
是一種約定,由Netscape公司 1995 年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS
、CSFR
等攻擊。所謂同源是指“協(xié)議+域名+端口”三者相同,即便兩個不同的域名指向同一個ip
地址,也非同源。
1、Cookie
、LocalStorage
和IndexDB
無法讀取
2、DOM
和Js
對象無法獲得
3、AJAX
請求不能發(fā)送
1)jsonp
跨域
關于jsonp
的原理把握一下幾點:
1、html
標簽的src
屬性沒有同源限制(支持跨域),瀏覽器解析script
標簽時,會自動下載src
屬性值(url
)指向的資源;
2、script
標簽指向的資源文件被下載后,其中的內(nèi)容會被立即執(zhí)行;
3、服務器端的程序會解析src
屬性值中的url
傳遞的參數(shù),根據(jù)這些參數(shù)針對性返回一個/
多個函數(shù)調(diào)用表達式,這些函數(shù)調(diào)用表達式的參數(shù)就是客戶端跨域想得到的數(shù)據(jù);
4、服務器生成、返回的文件中,表達式調(diào)用的函數(shù)是已經(jīng)在本地提前定義好的,而參數(shù)就是希望從跨域服務器拿到的數(shù)據(jù)。字面的script
標簽可以,動態(tài)添加到dom
樹中的script
也可以,后者更方便綁定事件。
5、只能實現(xiàn)get
,也是他的弱點
實現(xiàn):
// 服務端返回: test({ code: 0, message: "成功", });
<!-- 原生js --> <script> var script = document.createElement("script"); script.type = "text/javascript"; // 傳參并指定回調(diào)執(zhí)行函數(shù)為callback script.src = "http://www.chuchur.com/login?callback=test"; document.head.appendChild(script); // 回調(diào)執(zhí)行函數(shù) function test(res) { console.log(JSON.stringify(res)); } </script>
//jquery ajax: $.ajax({ url: "http://www.chuchur.com/login", type: "get", dataType: "jsonp", // 請求方式為jsonp jsonpCallback: "test", // 自定義回調(diào)函數(shù)名 data: {}, }); //vue.js this.$http .jsonp("http://www.chuchur.com/login", { params: {}, jsonp: "test", }) .then((res) => { console.log(res); });
2)document.domain + iframe
跨域
原理:這種方案只限于主域相同,子域不同的情況,其原理就是 兩個頁面通過js
強制設置window.domain
為主域,這樣就實現(xiàn)了同域。
實現(xiàn):
<!-- 父窗口 https://www.chuchur.com/a.html --> <iframe id="iframe" src="https://b.chuchur.com/b.html"></iframe> <script> document.domain = "chuchur.com"; var user = "chuchur"; </script> <!-- 子窗口 https://b.chuchur.com/b.html --> <script> document.domain = "chuchur.com"; // 獲取父窗口中變量 alert("從父窗口取得數(shù)據(jù)" + window.parent.user); </script>
3)location.hash + iframe
跨域
原理: 其原理就是通過URL
傳值,然后監(jiān)聽其hash
值的變化,然后通過中間層做跳板,再利用父子窗口js parent
最終來訪問同域所有頁面對象。
域 1: a.html
,域 2:b.html
,域 1:c.html
。
a.html
,b.html
不同域只能通過hash
傳值通訊。
b.html
,c.html
也不同域也只能單項通訊
a.html
,c.html
同域,所以c.html
可以通過parent
來訪問a.html
頁面對象
實現(xiàn):
1、a.html:(www.chuchur.com/a.html)
<iframe id="iframe" src="http://www.chuchur.org/b.html" style="display:none; " ></iframe> <script> var iframe = document.getElementById("iframe"); // 向b.html傳hash值 setTimeout(function () { iframe.src = iframe.src + "#nick=chuchur"; }, 1000); // 開放給同域c.html的回調(diào)方法 function test(res) { alert("數(shù)據(jù)來自c.html ---> " + res); } </script> `
2、b.html:(www.chuchur.org/b.html)
<iframe id="iframe" src="http://www.chuchur.com/c.html" style="display:none; " ></iframe> <script> var iframe = document.getElementById("iframe"); // 監(jiān)聽a.html傳來的hash值,再傳給c.html window.onhashchange = function () { iframe.src = iframe.src + location.hash; }; </script>
3、c.html:(www.chuchur.com/c.html)
<script> // 監(jiān)聽b.html傳來的hash值 window.onhashchange = function () { // 再通過操作同域a.html的js回調(diào),將結(jié)果傳回 window.parent.parent.test("你好: " + location.hash.replace("#nick=", "")); }; </script>
4)window.name + iframe
跨域
原理:利用window.name
特有屬性,name
值在不同的頁面甚至不同域 ,當頁面重新加載后依然存在,并且支持非常長的值,約 2MB
。
實現(xiàn):
// 1.)a.html:(www.chuchur.com/a.html) var proxy = function (url, callback) { var state = 0; var iframe = document.createElement("iframe"); // 加載跨域頁面 ,先讓頁面的name執(zhí)行賦值, iframe.src = url; // onload事件會觸發(fā)2次,第1次加載跨域頁,并留存數(shù)據(jù)于window.name iframe.onload = function () { if (state === 1) { // 第2次onload(同域proxy頁)成功后,讀取同域window.name中數(shù)據(jù) test(iframe.contentWindow.name); destoryFrame(); } else if (state === 0) { // 第1次onload(跨域頁)成功后,切換到同域代理頁面 iframe.contentWindow.location = "http://www.chuchur.com/b.html"; state = 1; } }; document.body.appendChild(iframe); // 獲取數(shù)據(jù)以后銷毀這個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:(www.chuchur.com/proxy.html), 這個頁面可以什么都不寫,但是要保證能正常訪問
<!-- 3.)b.html:(www.chuchur.org/b.html) --> <script> window.name = "我是一個可以非常長的變量"; </script>
5)postMessage
跨域
postMessage
是HTML5 XMLHttpRequest Level 2
中的API
,可以解決以下方面的問題:
a.)
頁面和其打開的新窗口的數(shù)據(jù)傳遞
b.)
多窗口之間消息傳遞
c.)
頁面與嵌套的iframe
消息傳遞
d.)
上面三個場景的跨域數(shù)據(jù)傳遞
用法:postMessage(data, origin)
方法接受兩個參數(shù)
data:html5
規(guī)范支持任意基本類型或可復制的對象,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()
序列化。
origin:
協(xié)議+主機+端口號,也可以設置為"\*
",表示可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置為"/
"。
實現(xiàn):
<!-- 1.)a.html:(www.chuchur.com/a.html) --> <iframe id="iframe" src="http://www.chuchur.com/b.html" style="display:none; " ></iframe> <script> var iframe = document.getElementById("iframe"); iframe.onload = function () { var data = { name: "邱秋", }; // 向chuchur.org傳送跨域數(shù)據(jù) iframe.contentWindow.postMessage( JSON.stringify(data), "http://www.chuchur.org" ); }; // 接受chuchur.org返回數(shù)據(jù) window.addEventListener( "message", function (e) { alert("我來自chuchur.org: " + e.data); }, false ); </script> <!-- 2.)b.html:(www.chuchur.org/b.html) --> <script> // 接收chuchur.com的數(shù)據(jù) window.addEventListener( "message", function (e) { alert("我來自chuchur.com " + e.data); var data = JSON.parse(e.data); if (data) { data.nick = chuchur; // 處理后再發(fā)回chuchur.com window.parent.postMessage( JSON.stringify(data), "http://www.chuchur.org" ); } }, false ); </script>
6)跨域資源共享(CORS
)
原理:普通跨域請求:只服務端設置Access-Control-Allow-Origin
即可,前端無須設置。
帶cookie
請求:前后端都需要設置字段,另外需注意:所帶cookie
為跨域請求接口所在域的cookie
,而非當前頁。 目前,所有瀏覽器都支持該功能(IE8+:IE8/9
需要使用XDomainRequest
對象來支持CORS
),CORS
也已經(jīng)成為主流的跨域解決方案。
實現(xiàn):
//1)原生js var xhr = new XMLHttpRequest(); // IE8/9需用window. XDomainRequest兼容 // 前端設置是否帶cookie xhr.withCredentials = true; xhr.open('post', 'http://www.chuchur.com/login', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('user=chuchur'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } }; //2.)jQuery ajax $.ajax({ ... xhrFields: { withCredentials: true // 前端設置是否帶cookie }, crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie ... }); //3.)vue框架在vue-resource封裝的ajax組件中加入以下代碼: Vue.http.options.credentials = true //后臺服務端 //java /* * 導入包:import javax.servlet.http. HttpServletResponse; * 接口參數(shù)中定義:HttpServletResponse response */ response.setHeader("Access-Control-Allow-Origin", "http://www.chuchur.com"); // 若有端口需寫全(協(xié)議+域名+端口) response.setHeader("Access-Control-Allow-Credentials", "true"); //node var server = http.createServer(); server.on('request', function(req, res) { var postData = ''; // 數(shù)據(jù)塊接收中 req.addListener('data', function(chunk) { postData += chunk; }); // 數(shù)據(jù)接收完畢 req.addListener('end', function() { postData = qs.parse(postData); // 跨域后臺設置 res.writeHead(200, { 'Access-Control-Allow-Credentials': 'true', // 后端允許發(fā)送Cookie 'Access-Control-Allow-Origin': 'http://www.chuchur.com', // 允許訪問的域(協(xié)議+域名+端口) 'Set-Cookie': 'l=abcdef; Path=/; Domain=www.chuchur.com; HttpOnly' // HttpOnly: 腳本無法讀取cookie }); res.write(JSON.stringify(postData)); res.end(); }); }); server.listen('3000');
7)nginx
反向代理跨域
瀏覽器跨域訪問js
、css
、img
等常規(guī)靜態(tài)資源被同源策略許可,但iconfont
字體文件(eot|otf|ttf|woff|svg
)例外,此時可在nginx
的靜態(tài)資源服務器中加入以下配置。
location / { add_header Access-Control-Allow-Origin *; }
原理:通過nginx
代理一個 同域不同端口的跳板機,反向代理要跨域的域名,這樣可以修改cookie
里面的domain
信息實現(xiàn)跨域
實現(xiàn):
#nginx具體配置: server { listen 80; server_name www.chuchur.com; location / { proxy_pass http://www.chuchur.org; #反向代理 proxy_cookie_domain www.chuchur.org www.chuchur.com; #修改cookie里域名 index index.html index.htm; # 當用webpack-dev-server等中間件代理接口訪問nignx時,此時無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啟用 add_header Access-Control-Allow-Origin http://www.chuchur.com; #當前端只跨域不帶cookie時,可為* add_header Access-Control-Allow-Credentials true; } }
前端實現(xiàn)
var xhr = new XMLHttpRequest(); // 前端開關:瀏覽器是否讀寫cookie xhr.withCredentials = true; // 訪問nginx中的代理服務器 xhr.open('get', 'http://www.chuchur.com/?user=chuchur', true); xhr.send(); // node var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前臺寫cookie res.writeHead(200, { 'Set-Cookie': 'l=abcdef; Path=/; Domain=www.chuchur.org; HttpOnly' // HttpOnly: 腳本無法讀取 }); res.write(JSON.stringify(params)); res.end(); }); server.listen('8080');
8)Nodejs
中間件代理跨域
原理同nignx
代理跨域類似,都是通過代理服務器實現(xiàn)數(shù)據(jù)轉(zhuǎn)發(fā)
實現(xiàn):
//1)利用中間件http-proxy-middleware實現(xiàn) var express = require('express'); var proxy = require('http-proxy-middleware'); var app = express(); app.use('/', proxy({ // 代理跨域目標接口 target: 'http://www.chuchur.org:', changeOrigin: true, // 修改響應頭信息,實現(xiàn)跨域并允許帶cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', 'http://www.chuchur.com'); res.header('Access-Control-Allow-Credentials', 'true'); }, // 修改響應信息中的cookie域名 cookieDomainRewrite: 'www.chuchur.com' // 可以為false,表示不修改 })); app.listen(3000); //2)利用中間件 webpack-dev-server實現(xiàn) //webpack.config.js部分配置: module.exports = { entry: {}, module: {}, ... devServer: { historyApiFallback: true, proxy: [{ context: '/login', target: 'http://www.chuchur.org', // 代理跨域目標接口 changeOrigin: true, cookieDomainRewrite: 'www.chuchur.com' // 可以為false,表示不修改 }], noInfo: true } }
9)WebSocket
協(xié)議跨域
WebSocket protocol
是HTML5
一種新的協(xié)議。它實現(xiàn)了瀏覽器與服務器全雙工通信,同時允許跨域通訊,是server push
技術(shù)的一種很好的實現(xiàn)。原生WebSocket API
使用起來不太方便,我們使用Socket.io
,它很好地封裝了webSocket
接口,提供了更簡單、靈活的接口,也對不支持webSocket
的瀏覽器提供了向下兼容。
實現(xiàn):
1、前端代碼
<div>user input:<input type="text" /></div> <script src="./socket.io.js"></script> <script> var socket = io("http://www.chuchur.org"); // 連接成功處理 socket.on("connect", function () { // 監(jiān)聽服務端消息 socket.on("message", function (msg) { console.log("來自服務器的消息: " + msg); }); // 監(jiān)聽服務端關閉 socket.on("disconnect", function () { console.log("Server socket has closed."); }); }); document.getElementsByTagName("input")[0].onblur = function () { socket.send(this.value); }; </script>
2、Nodejs socket
后臺:
var http = require('http'); var socket = require('socket.io'); // 啟http服務 var server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html' }); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080... '); // 監(jiān)聽socket連接 socket.listen(server).on('connection', function(client) { // 接收信息 client.on('message', function(msg) { client.send('哈哈:' + msg); console.log('來自客服端的消息': -- - > ' + msg); }); // 斷開處理 client.on('disconnect', function() { console.log('Client socket has closed.'); }); });
以上 9 種方式都能實現(xiàn)跨域數(shù)據(jù)傳遞,用的最多的還是第六種跨域資源共享(CORS
),在前后端分離開發(fā)模式最常見。第七種和第八種中間件代理實現(xiàn)方式則是在基于node
開發(fā)種常用的
其中第二,三、四、五種方案 ,利用ifame
和postMessage
則可以實現(xiàn) 不同窗口之間的數(shù)據(jù)通訊。
以上是“WEB前端跨域的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
標題名稱:WEB前端跨域的示例分析
網(wǎng)頁URL:http://muchs.cn/article6/ihipog.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、、App設計、用戶體驗、虛擬主機、動態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)