前言
前端通信类的问题,主要包括以下内容:
- 1、什么是同源策略及限制
- 2、前后端如何通信
- 3、如何创建Ajax
- 4、跨域通信的几种方式
同源策略的概念和具体限制
同源策略:限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自MDN官方的解释)
具体解释:
(1)源
包括三个部分:协议、域名、端口(http协议的默认端口是80)。如果有任何一个部分不同,则源
不同,那就是跨域了。
(2)限制
:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:(要记住)
-
Cookie、LocalStorage和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
跨域通信的几种方式
方式如下:
-
1、JSONP
-
2、WebSocket
-
3、CORS
-
4、Hash
-
5、postMessage
-
6、转发代理
1、JSONP
面试会问:JSONP的原理是什么?怎么实现的?
在CORS和postMessage以前,我们一直都是通过JSONP来做跨域通信的。
JSONP的原理:通过<script>
标签的异步加载来实现的。比如说,实际开发中,我们发现,head标签里,可以通过<script>
标签的src,里面放url,加载很多在线的插件。这就是用到了JSONP。
比如说,客户端这样写:
<script src="http://www.smyhvae.com/?data=name&callback=myjsonp"></script>
上面的src中,data=name
是get请求的参数,myjsonp
是和后台约定好的函数名。
服务器端这样写:
-
myjsonp({
-
data: {}
-
})
于是,本地要求创建一个myjsonp 的全局函数,才能将返回的数据执行出来。
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.');
-
};
3、CORS
CORS 可以理解成是既可以同步、也可以异步*的Ajax。
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()方法
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.com
-
console.log(event.source); //获取:A window对象
-
console.log(event.data); //获取传过来的数据
-
}, false);
6、转发代理
我们知道同源策略只是在浏览器中存在,不存在于服务器中。因此我们可以将需要跨域请求的地址转发给我们自己的服务器然后委托服务器去请求信息。在VUE项目中,axios不支持跨域,如果需要跨域访问接口,则需要用到转发代理proxy
在config\index.js文件中修改配置信息
proxyTable: { //转发代理 '/activity':{ target:'http://10.136.197.42:3000', changeOrigin: true } }
在axios模块不设置默认baseurl