1.什么是同源策略和限制?
同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互;所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。
限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:Cookie、LocalStorage和IndexDB无法获取。
-
无法获取和操作DOM。
-
不能发送Ajax请求。我们要注意,Ajax只适合同源的通信。
2.前后端如何通信?
ajax、websocket和cors
ajax同源通信, websocket不限制同源通信, CORS支持跨域,也支持同源通信。
2.1 如何创建ajax?
-
XMLHttpRequest 的工作原理
-
兼容性处理(XMLHttpRequest只有在高级浏览器中才支持。)
-
事件的触发条件
-
事件的触发顺序
-
当请求一切正常时,相关的事件触发顺序如下: 1.触发xhr.onreadystatechange(之后每次readyState变化时。都会触发一次) 2.触发xhr.onloadstart 上传阶段开始: 3.触发xhr.upload.onloadstart 4.xhr.upload.onprogress 5.xhr.upload.onload 6.xhr.upload.onloadend 上传结束,下载阶段开始 7.xhr.onprogress 8.xhr.onload 9.xhr.onloadend
XMLHttpRequest有很多触发事件,每个事件是怎么触发的。
2.2发送 Ajax 请求的五个步骤(XMLHttpRequest的工作原理)
(1)创建XMLHttpRequest 对象。
var xhr= new XMLHttpRequest();
(2)使用open方法设置请求的参数。open(method, url, 是否异步)。
//设置请求的参数。包括:请求的方法、请求的url
xhr.open('get','url');
xhr.open('post','url');
(3)发送请求。
//get方法发送请求
xhr.send()
//post 方法发送请求
// 如果想要使用post提交数据,必须添加此行
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
xhr.send('name=zhangsan&age=19');
(4)注册事件。 注册onreadystatechange事件,状态改变时就会调用。
// 发送并接受返回值
xhr.onreadystatechange = function (){
// 这步为判断服务器是否正确响应
if (xhr.readyState = 4 && xhr.status == 200){
// 获取返回的数据,更新dom
response = xhr.responseText
}
}
如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。
(5)获取返回的数据,更新UI。
2.3 onreadystatechange 事件
注册 onreadystatechange 事件后,每当 readyState 属性改变时,就会调用 onreadystatechange 函数。
readyState:(存有 XMLHttpRequest 的状态。从 0 到 4 发生变化)
-
0: 请求未初始化
-
1: 服务器连接已建立
-
2: 请求已接收
-
3: 请求处理中
-
4: 请求已完成,且响应已就绪
2.4 原生ajax请求
// 原生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);
}
}
}
}
3.跨域通信的几种方式?
jsonp、hash、postMessage、websocket、cors
ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。
3.1 jsonp
基本原理: 主要就是利用了 script
标签的src
没有跨域限制来完成的
// 创建一个jsonpCallback函数。但是它还没有被调用
// 加载src中的资源,并等待请求的内容返回
<script type='text/javascript'>
window.jsonpCallback = function (res) {
console.log(res)
}
</script>
<script src='http://localhost:8080/api/jsonp?id=1&callback=jsonpCallback' type='text/javascript'></script>
3.2 WebSocket
var ws = new WebSocket('wss://'); //创建WebSocket的对象。参数可以是 ws 或 wss,后者表示加密。
// 方法在连接成功时,触发
ws.onopen = function (evt) {
console.log("websocket连接成功");
};
// 监听连接失败
ws.onerror = function(){
console.log("连接失败...");
// 重新连接
}
// message 事件会在 WebSocket 接收到新消息时被触发。
ws.onmessage = function (data) {
console.log("收消息onmessage---", data);
};
//WebSocket.close() 方法关闭 WebSocke连接或连接尝试(如果有的话)。 如果连接已经关闭,则此方法不执行任何操作。
ws.onclose = function (evt) {
console.log('close.');
};
3.3、CORS
CORS 可以理解成是既可以同步、也可以异步*的Ajax。
fetch 是一个比较新的API,用来实现CORS通信。用法如下:
cors支持跨域通信:跨域时,浏览器会拦截Ajax请求,并在http头中加Origin。
3.4.hash
url的#
后面的内容就叫Hash。Hash的改变,页面不会刷新。这就是用 Hash 做跨域通信的基本原理。
补充:url的?
后面的内容叫Search。Search的改变,会导致页面刷新,因此不能做跨域通信。
页面A中:
var B = document.getElementsByTagName('iframe');
B.src = B.src + '#' + 'jsonString'; //我们可以把JS 对象,通过 JSON.stringify()方法转成 json字符串,发给 B
B页面中:
window.onhashchange = function () { //通过onhashchange方法监听,url中的 hash 是否发生变化
var data = window.location.hash;
};
5.postMessage
postMessage 推送 ,window.addEventListener接收使用
发送方使用postMessage方法向接收方推送消息,第一个参数为推送的内容,第二个参数是允许被访问的域名;
接收方通过window.addEventListener监听message的方法接收数据。
iframe引入页面(我也是使用这样方式)
在A页面中通过iframe的src放b页面的访问地址
// url是需要接收传递消息的地址
<iframe id="IframeTest"
src="${url}"
height="100%" width="100%" style="border: none">
</iframe>
A页面获取iframe,发送消息
// http://localhost:8000/#/ 是限制通信的具体地址,*代表是不限制地址
var iframe = document.getElementById("IframeTest")
iframe.contentWindow.postMessage({
text:'消息内容',
text2: '内容2' // action : 自定义动作参数,用于接受收消息是的判断
}, 'http://localhost:8000/#/');
若A页面也需要B 页面传过来的数据,
//这是接收子页面返回的监听(如果只父页面发送消息不需要在接收子页面的反馈可以不用写这些)
window.addEventListener('message', function (e) {
alert(e.data)
const data = e.data;
console.log('子页面传过来的消息')
})
B页面中(子页面中)
// 若是vue页面,可以写在mounted中接收
window.addEventListener('message', (e) => {
console.log(e)
let data= e.data //这就是接收到的数据
})
若在B页面需要给A页面传信息,触发A页面的
window.top.postMessage('{"text":"这是子页面传出去的信息", '*')