前端跨域通信的幾種方式

前言

前端通信類的問題,主要包括以下內容:

  • 1、什么是同源策略及限制

同源策略是一個概念,就一句話。有什么限制,就三句話。能說出來即可。

  • 2、前后端如何通信

如果你不準備,估計也就只能說出ajax。

  • 3、如何創建Ajax

Ajax在前后端通信中經常用到。做業務時,可以借助第三方的庫,比如vue框架里的庫、jQuery也有封裝好的方法。但如果讓你用原生的js去實現,該怎么做?

這就是考察你的動手能力,以及框架原理的掌握。如果能寫出來,可以體現出你的基本功。

  • 4、跨域通信的幾種方式

這部分非常重要。無非就是問你:什么是跨域、跨域有什么限制、跨域有幾種方式

下面分別講解。

同源策略的概念和具體限制

同源策略:限制從一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用于隔離潛在惡意文件的關鍵的安全機制。(來自MDN官方的解釋)

具體解釋:

(1)包括三個部分:協議、域名、端口(http協議的默認端口是80)。如果有任何一個部分不同,則不同,那就是跨域了。

(2)限制:這個源的文檔沒有權利去操作另一個源的文檔。這個限制體現在:(要記住)

  • Cookie、LocalStorage和IndexDB無法獲取。

  • 無法獲取和操作DOM。

  • 不能發送Ajax請求。我們要注意,Ajax只適合同源的通信。

前后端如何通信

主要有以下幾種方式:

  • Ajax:不支持跨域。

  • WebSocket:不受同源策略的限制,支持跨域。

  • CORS:不受同源策略的限制,支持跨域。一種新的通信協議標準。可以理解成是:同時支持同源和跨域的Ajax

如何創建Ajax

關于Ajax請求,可以看本人的基礎文章:Ajax入門和發送http請求

在回答 Ajax 的問題時,要回答以下幾個方面:

  • 1、XMLHttpRequest 的工作原理

  • 2、兼容性處理

XMLHttpRequest只有在高級瀏覽器中才支持。在回答問題時,這個兼容性問題不要忽略。

  • 3、事件的出發條件

  • 4、事件的觸發順序

XMLHttpRequest有很多觸發事件,每個事件是怎么觸發的。

發送 Ajax 請求的五個步驟(XMLHttpRequest的工作原理)

(1)創建XMLHttpRequest 對象。

(2)使用open方法設置請求的參數。open(method, url, 是否異步)。

(3)發送請求。

(4)注冊事件。 注冊onreadystatechange事件,狀態改變時就會調用。

如果要在數據完整請求回來的時候才調用,我們需要手動寫一些判斷的邏輯。

(5)獲取返回的數據,更新UI。

發送 get 請求和 post 請求

get請求舉例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body>
<h1>Ajax 發送 get 請求</h1>
<input type="button" value="發送get_ajax請求" id='btnAjax'><script type="text/javascript">// 綁定點擊事件document.querySelector('#btnAjax').onclick = function () {// 發送ajax 請求 需要 五步// (1)創建異步對象var ajaxObj = new XMLHttpRequest();// (2)設置請求的參數。包括:請求的方法、請求的url。ajaxObj.open('get', '02-ajax.php');// (3)發送請求ajaxObj.send();//(4)注冊事件。 onreadystatechange事件,狀態改變時就會調用。//如果要在數據完整請求回來的時候才調用,我們需要手動寫一些判斷的邏輯。ajaxObj.onreadystatechange = function () {// 為了保證 數據 完整返回,我們一般會判斷 兩個值if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {// 如果能夠進到這個判斷 說明 數據 完美的回來了,并且請求的頁面是存在的// 5.在注冊的事件中 獲取 返回的 內容 并修改頁面的顯示console.log('數據返回成功');// 數據是保存在 異步對象的 屬性中console.log(ajaxObj.responseText);// 修改頁面的顯示document.querySelector('h1').innerHTML = ajaxObj.responseText;}}}
</script>
</body>
</html>

post 請求舉例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body>
<h1>Ajax 發送 get 請求</h1>
<input type="button" value="發送put_ajax請求" id='btnAjax'>
<script type="text/javascript">// 異步對象var xhr = new XMLHttpRequest();// 設置屬性xhr.open('post', '02.post.php');// 如果想要使用post提交數據,必須添加此行xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");// 將數據通過send方法傳遞xhr.send('name=fox&age=18');// 發送并接受返回值xhr.onreadystatechange = function () {// 這步為判斷服務器是否正確響應if (xhr.readyState == 4 && xhr.status == 200) {alert(xhr.responseText);}};
</script>
</body>
</html>

onreadystatechange 事件

注冊 onreadystatechange 事件后,每當 readyState 屬性改變時,就會調用 onreadystatechange 函數。

readyState:(存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化)

  • 0: 請求未初始化

  • 1: 服務器連接已建立

  • 2: 請求已接收

  • 3: 請求處理中

  • 4: 請求已完成,且響應已就緒

事件的觸發條件

事件的觸發順序

上圖的參考鏈接:

  • 你真的會使用XMLHttpRequest嗎?

實際開發中用的 原生Ajax請求

var util = {};//獲取 ajax 請求之后的jsonutil.json = function (options) {var opt = {url: '',type: 'get',data: {},success: function () {},error: function () {},};util.extend(opt, options);if (opt.url) {//IE兼容性處理:瀏覽器特征檢查。檢查該瀏覽器是否存在XMLHttpRequest這個api,沒有的話,就用IE的apivar xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP');var data = opt.data,url = opt.url,type = opt.type.toUpperCase();dataArr = [];}for (var key in data) {dataArr.push(key + '=' + data[key]);}if (type === 'GET') {url = url + '?' + dataArr.join('&');xhr.open(type, url.replace(/\?$/g, ''), true);xhr.send();}if (type === 'POST') {xhr.open(type, url, true);// 如果想要使用post提交數據,必須添加此行xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");xhr.send(dataArr.join('&'));}xhr.onload = function () {if (xhr.status === 200 || xhr.status === 304) { //304表示:用緩存即可。206表示獲取媒體資源的前面一部分var res;if (opt.success && opt.success instanceof Function) {res = xhr.responseText;if (typeof res === 'string') {res = JSON.parse(res);  //將字符串轉成jsonopt.success.call(xhr, res);}}} else {if (opt.error && opt.error instanceof Function) {opt.error.call(xhr, res);}}};}

Ajax 的推薦鏈接:https://segmentfault.com/a/1190000006669043

跨域通信的幾種方式

方式如下:

  • 1、JSONP

  • 2、WebSocket

  • 3、CORS

  • 4、Hash

  • 5、postMessage

上面這五種方式,在面試時,都要說出來。

1、JSONP

面試會問:JSONP的原理是什么?怎么實現的?

在CORS和postMessage以前,我們一直都是通過JSONP來做跨域通信的。

JSONP的原理:通過<script>標簽的異步加載來實現的。比如說,實際開發中,我們發現,head標簽里,可以通過<script>標簽的src,里面放url,加載很多在線的插件。這就是用到了JSONP。

JSONP的實現:

比如說,客戶端這樣寫:

<script src="http://www.smyhvae.com/?data=name&callback=myjsonp"></script>

上面的src中,data=name是get請求的參數,myjsonp是和后臺約定好的函數名。
服務器端這樣寫:

myjsonp({data: {}
})

于是,本地要求創建一個myjsonp 的全局函數,才能將返回的數據執行出來。

實際開發中,前端的JSONP是這樣實現的:

<script>var util = {};//定義方法:動態創建 script 標簽/*** [function 在頁面中注入js腳本]* @param  {[type]} url     [description]* @param  {[type]} charset [description]* @return {[type]}         [description]*/util.createScript = function (url, charset) {var script = document.createElement('script');script.setAttribute('type', 'text/javascript');charset && script.setAttribute('charset', charset);script.setAttribute('src', url);script.async = true;return script;};/*** [function 處理jsonp]* @param  {[type]} url      [description]* @param  {[type]} onsucess [description]* @param  {[type]} onerror  [description]* @param  {[type]} charset  [description]* @return {[type]}          [description]*/util.jsonp = function (url, onsuccess, onerror, charset) {var callbackName = util.getName('tt_player'); //事先約定好的 函數名window[callbackName] = function () {      //根據回調名稱注冊一個全局的函數if (onsuccess && util.isFunction(onsuccess)) {onsuccess(arguments[0]);}};var script = util.createScript(url + '&callback=' + callbackName, charset);   //動態創建一個script標簽script.onload = script.onreadystatechange = function () {   //監聽加載成功的事件,獲取數據if (!script.readyState || /loaded|complete/.test(script.readyState)) {script.onload = script.onreadystatechange = null;// 移除該script的 DOM 對象if (script.parentNode) {script.parentNode.removeChild(script);}// 刪除函數或變量window[callbackName] = null;  //最后不要忘了刪除}};script.onerror = function () {if (onerror && util.isFunction(onerror)) {onerror();}};document.getElementsByTagName('head')[0].appendChild(script); //往html中增加這個標簽,目的是把請求發送出去};</script>

2、WebSocket

WebSocket的用法如下:

//var ws = new WebSocket('wss://echo.websocket.org'); //創建WebSocket的對象。參數可以是 ws 或 wss,后者表示加密。//把請求發出去ws.onopen = function (evt) {console.log('Connection open ...');ws.send('Hello WebSockets!');};//對方發消息過來時,我接收ws.onmessage = function (evt) {console.log('Received Message: ', evt.data);ws.close();};//關閉連接ws.onclose = function (evt) {console.log('Connection closed.');};

Websocket的推薦鏈接:http://www.ruanyifeng.com/blog/2017/05/websocket.html

3、CORS

CORS 可以理解成是既可以同步、也可以異步*的Ajax。

fetch 是一個比較新的API,用來實現CORS通信。用法如下:

// url(必選),options(可選)fetch('/some/url/', {method: 'get',}).then(function (response) {  //類似于 ES6中的promise}).catch(function (err) {// 出錯了,等價于 then 的第二個參數,但這樣更好用更直觀});
  • CORS的推薦鏈接:http://www.ruanyifeng.com/blog/2016/04/cors.html

推薦鏈接里有詳細的配置。

另外,如果面試官問:“CORS為什么支持跨域的通信?”

答案:跨域時,瀏覽器會攔截Ajax請求,并在http頭中加Origin。

4、Hash

url的#后面的內容就叫Hash。Hash的改變,頁面不會刷新。這就是用 Hash 做跨域通信的基本原理。

補充:url的?后面的內容叫Search。Search的改變,會導致頁面刷新,因此不能做跨域通信。

使用舉例:

場景:我的頁面 A 通過iframe或frame嵌入了跨域的頁面 B。

現在,我這個A頁面想給B頁面發消息,怎么操作呢?

(1)首先,在我的A頁面中:

//偽代碼var B = document.getElementsByTagName('iframe');B.src = B.src + '#' + 'jsonString';  //我們可以把JS 對象,通過 JSON.stringify()方法轉成 json字符串,發給 B

(2)然后,在B頁面中:

 // B中的偽代碼window.onhashchange = function () {  //通過onhashchange方法監聽,url中的 hash 是否發生變化var data = window.location.hash;};

5、postMessage()方法

H5中新增的postMessage()方法,可以用來做跨域通信。既然是H5中新增的,那就一定要提到。

場景:窗口 A (http:A.com)向跨域的窗口 B (http:B.com)發送信息。步驟如下。

(1)在A窗口中操作如下:向B窗口發送數據:

// 窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息Bwindow.postMessage('data', 'http://B.com'); //這里強調的是B窗口里的window對象

(2)在B窗口中操作如下:

// 在窗口B中監聽 message 事件Awindow.addEventListener('message', function (event) {   //這里強調的是A窗口里的window對象console.log(event.origin);  //獲取 :url。這里指:http://A.comconsole.log(event.source);  //獲取:A window對象console.log(event.data);    //獲取傳過來的數據}, false);

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249154.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249154.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249154.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

T4((Text Template Transformation Toolkit))模版引擎之基礎入門 C#中文本模板(.tt)的應用...

1 關于C#中文本模板(.tt)的簡單應用https://blog.csdn.net/zunguitiancheng/article/details/78011145 任何一個傻瓜都能寫出計算機能理解的程序&#xff0c;而優秀的程序員卻能寫出別人能讀得懂的程序。—— Martin Fowler 2 T4模版引擎之生成數據庫實體類 http://www.cnblogs…

LeetCode412Fizz Buzz

寫一個程序&#xff0c;輸出從 1 到 n 數字的字符串表示。 1. 如果 n 是3的倍數&#xff0c;輸出“Fizz”&#xff1b; 2. 如果 n 是5的倍數&#xff0c;輸出“Buzz”&#xff1b; 3.如果 n 同時是3和5的倍數&#xff0c;輸出 “FizzBuzz”。 示例&#xff1a; n 15, 返回: [ …

vue+node實現中間層同步調用接口

為了應對業務的復雜性&#xff0c;提高前端的渲染能力&#xff0c;故在項目中引入nodejs做中間層&#xff0c;前端承接vue&#xff0c;后端對接Java。 至于為什么這么搞&#xff0c;網上有好多文章都在討論&#xff0c;可以說仁者見仁智者見智&#xff0c;這里我們不在深究。 …

ES6學習筆記(二十二)ArrayBuffer

ArrayBuffer ArrayBuffer對象、TypedArray視圖和DataView視圖是 JavaScript 操作二進制數據的一個接口。它們都是以數組的語法處理二進制數據&#xff0c;所以統稱為二進制數組。 二進制數組由三類對象組成。 &#xff08;1&#xff09;ArrayBuffer對象&#xff1a; 代表內存之…

如何正確地使用Java的@deprecated標注

沒有什么事情比看到一個沒有任何說明的deprecated標注更讓人憤怒的事情了。這種做法只能讓人困惑&#xff0c;我到底還要不要用這個已經‘廢棄’的方法&#xff1f;如果開發者不希望某個方法再被人用的話&#xff0c;就要好好地為deprecated標注寫說明。這篇文章就討論了正確地…

實現div里的img圖片水平垂直居中

body結構 <body><div><img src"1.jpg" alt"haha"></div> </body>方法一&#xff1a; 將display設置成table-cell&#xff0c;然后水平居中設置text-align為center&#xff0c;垂直居中設置vertical-align為middle。 <…

[ 懶人神器 ] —— OO一鍵build:.zip - .jar

懶人神器 更新 大家注意一下&#xff0c;由于在寫入MANIFEST的時候&#xff0c;Class-Path路徑給的是 ../lib &#xff0c;即上級目錄的lib。 所以在對拍時如果手動移動了 jar包的位置&#xff0c;需要保證 lib/ 文件夾在存放jar包的上一級目錄下&#xff0c;否則在運行時會報錯…

實現Datagrid分頁

Html頁面&#xff1a; <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title></title><meta charset"utf-8" /><!-- 引入相關CSS --><…

Luogu 3698 [CQOI2017]小Q的棋盤

BZOJ 4813 雖然數據范圍很迷人&#xff0c;但是想樹形$dp$沒有前途。 先發現一個事情&#xff0c;就是我們可以先選擇一條鏈&#xff0c;最后要走到這一條鏈上不回來&#xff0c;走到鏈上的點每一個只需要一步&#xff0c;而如果要走這條鏈之外的點&#xff0c;一個點需要走兩步…

h5-plus.webview

這里是鏈接轉載于:https://www.cnblogs.com/yuners/p/10721163.html

解決vue打包后靜態資源路徑錯誤的問題

vue項目完成的最后一步就是打包部署上線&#xff0c;但是打包部署的過程往往不是那么一帆風順的&#xff0c;現將遇到問題和解決方案記錄如下。 圖片路徑問題 起因&#xff1a; 頁面中引入資源的方式往往有如下幾種 * HTML標簽中直接引入圖片&#xff0c; 如 <img src&qu…

SQL語句01

SQL(Structured Query Language)&#xff1a;結構化查詢語言SQL分類&#xff1a; 數據操縱語言DML&#xff08;Data Manipulation Language&#xff09; SELECT INSERT UPDATE DELETE 數據定義語言DDL&#xff08;Data definition language&#xff09; …

mongoose 筆記

快速啟動 首先需要安裝MongoDB和Node.js。 然后使用npm下載mongoose&#xff1a; npm install mongoose 接著我們直接在項目中引入mongoose&#xff0c;并且連接數據庫就會在本地運行 MongoDB了&#xff1a; // index.js var mongoose require(mongoose); mongoose.connect(…

前端DES加密

1、下載crypto.js文件庫 https://github.com/brix/crypto-js/releases 2、引入文件 <script type"text/javascript" src"js/jquery.min.js"></script> <script src"js/rollups/tripledes.js"></script> <script src&…

DOMBOM(source、methods、contents、Application)

何為DOM&#xff1f; Document Object Model Dom&#xff0c;是W3C組織推薦的處理可擴展標志語言的標準編程接口。在網頁上&#xff0c;組織頁面的對象被組織在一個樹形結構中&#xff0c;用來表示文檔中對象的標準模型就稱為DOM。 可以認為DOM是頁面上數據和結構的一個樹形表示…

sublime 無法下載插件解決辦法(親測有效)

最近發現sublime裝不到插件 只需要在Preferences > Package Settings > Package Control > Settings - User頁面加上以下代碼即可&#xff1a; "channels":["https://erhan.in/channel_v3.json"]上述頻道親測有效&#xff0c;如果還不能使用的小…

ES命令

基礎概念 Elasticsearch有幾個核心概念。從一開始理解這些概念會對整個學習過程有莫大的幫助。 接近實時&#xff08;NRT&#xff09; Elasticsearch是一個接近實時的搜索平臺。這意味著&#xff0c;從索引一個文檔直到這個文檔能夠被搜索到有一個輕微的延遲&#xff…

Bug : Bash on Ubuntu on Windows scp work on window but not in shell file

&#xff1a; No Permission轉載于:https://www.cnblogs.com/rgqancy/p/10726154.html

圖片做背景撐開div

需求點&#xff1a; 設計師給了一張超大背景圖&#xff0c;需要做一個不知道大小廣告位&#xff0c;要求就是要把圖片撐滿整個頁面&#xff0c;而且還得保證自適應。 解決方案一 &#xff08;親測有效&#xff09; HTML代碼&#xff1a; <div class"wrap">…

十一、jQuery的基本用法

初步接觸不是很習慣&#xff0c;之前都是用的js&#xff0c;但是jQuery去掉了js很多繁瑣的內容&#xff0c;用的不是很熟&#xff0c;所以先簡單的記錄一下&#xff0c;后續在繼續補充 jq獲取html內容: $("#id") 獲取id $(".class") class名 …