前端通信跨域
Posted lhh520
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端通信跨域相关的知识,希望对你有一定的参考价值。
首先了解什么是同源策略:
限制一个源加载的文档或脚本与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自MDN的解释)
源包括三个部分:协议、域名、端口(HTTP协议的默认端口是80)。如果其中有任何一个部分不同,则源不同。即为跨域。
限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:
Cookie、LlocalStorage和IndexDB无法获取;
无法获取和操作DOM;
不能发送Ajax请求。(Ajax只适合同源的通信)。
前后端的通信方式:
Ajax:不支持跨域;
WebSocket:不受同源策略的限制,支持跨域;
CORS:不受同源策略的限制,支持跨域;一种新的通信协议标准。可以理解成同时支持同源和跨域的Ajax。
如何创建Ajax:
在回答 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:请求已完成,且响应已就绪
事件的触发条件
事件的触发顺序
原生Ajax请求
var util = {}; //获取 ajax 请求之后的json util.json = function (options) { var opt = { url: ‘‘, type: ‘get‘, data: {}, success: function () { }, error: function () { }, }; util.extend(opt, options); if (opt.url) { //IE兼容性处理:浏览器特征检查。检查该浏览器是否存在XMLHttpRequest这个api,没有的话,就用IE的api var 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); //将字符串转成json opt.success.call(xhr, res); } } } else { if (opt.error && opt.error instanceof Function) { opt.error.call(xhr, res); } } }; }
跨域通信的几种方式:
1.JSONP
2.WebSocket
3.CORS
4.Hash
5.postMessage
1.JSONP
原理:通过<script>标签的异步加载来实现。例如通过<script>标签的src,里面放url,加载一些插件,就用到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
代码实例如下:
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.‘); };
3.CORS
fetch是一个比较新的API,用来实现CORS通信。用法如下:
// url(必选),options(可选) fetch(‘/some/url/‘, { method: ‘get‘, }).then(function (response) { //类似于 ES6中的promise }).catch(function (err) { // 出错了,等价于 then 的第二个参数,但这样更好用更直观 });
另外,如果面试官问:“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()方法
场景:窗口 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.com console.log(event.source); //获取:A window对象 console.log(event.data); //获取传过来的数据 }, false);
参考:
https://www.cnblogs.com/smyhvae/p/8523576.html
以上是关于前端通信跨域的主要内容,如果未能解决你的问题,请参考以下文章