1.什么是同源策略及限制
1.同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。 ( 这是一个用于隔离潜在恶意文件的关键的安全机制。)
2.一个源包括:协议、域名、端口(这三个有一个不一样就是源不一样,就是我们所说的跨域了)http:// 协议域名没指名端口默认803.限制:不是一个源的文档没有权利去操作另一个源的文档;
主要限制在几个方面:
- Cookie、LocalStorage 和 IndexDB 无法读取--操作不了Cookie、LocalStorage、IndexDB
- DOM无法获得--无法获取和操作另一个资源的DOM
- Ajax请求不能发送(同源下的通信方式)--Ajax只适合同源的通信(跨域就不行了)
2.前后端如何通信
1、Ajax
--同源下的通信方式2、WebSocket--不受同源策略的限制3、CORS--支持跨域通信,也支持同源通信
3.如何创建Ajax
1、XMLHttpRequest对象的工作流程
2、兼容性处理3、事件的触发条件4、事件的触发顺序
function ajax(url,fnSucc,fnFaild){ //1、创建一个对象(兼容IE6写法) var xhr = XMLHttpRequest ? new XMLHttpRequest(): new ActiveXObject('Microsoft.XMLHTTP'); //2、连接服务器,确定对象的发送方式:xhr.open(type,url,true); xhr.open('GET',url,true); //3、发送请求 xhr.send(); //4、接受服务器返回(响应) xhr.onreadyStateChange = function(){ if(xhr.readyState == 4){ //完成 //如果加载媒体资源需要再加上xhr.status===206 (媒体资源特别大,不是一次性返回过来的,是资源的一部分;服务端给你下发的http状态码是206,这个地方不加206,是收不到响应的) if (xhr.status === 200 || xhr.status === 304) { fuSucc(xhr.responseText); }else{ if(fnFaild){ fnFaild(xhr.status); } } } };}
4.跨域通信的几种方式
1、JSONP
1.在什么时候用: --在出现postMessage、CORS之前一直用JSONP做跨域通信的; 2.怎么做到的: -- 利用script标签的异步加载来实现的; (一个页面是www.immoc.com,script标签地址的域名100%不是(js的地址和域名是不一致的), 跨源了,不影响script加载)--这就是jsonp能够实行的一个最初的基本原理; 3.怎么实现的: --需要给服务端传递一个回调的名,这个回调的名就是我用加载script标签的方式发出一个请求去, 你给我返回一块内容,这个内容是一个js块也就是script的块,这个块中有回调名加代码就能运行了, --原理:(利用这个发出请求了,告诉服务端callback的名称,将来要作为函数名来返回的,既然是函数名,要创建一个函数,所以在调jsonp的时候 ,本地必须有一个jsonp的这么全局函数,后面才能把给的数据能执行出来,当函数来运行。) callback后面名字叫什么都可以; -告诉它一个回调的名称,而且要在window注册一个全局的一个函数,然后下面的createScript就是要动态创建一个script标签,最后返回这个东西。最后script.onload是监听脚本的加载事件,如果响应完了,也会响应onload,然后判断onload是不是成功,成功了以后看能不能拿到那个数据。最后不要忘了删除这个函数变量window[callbackName]=null;最后往html中增加script标签目的就是把这个请求发送出去。 3.1.1.服务器给你下发的是一个script内容,利用回调的东西,执行了后面的代码 jsonp.js: box({name:'xxx'}); function createJs(sUrl){ var oScript = document.createElement('script'); oScript.type = "text/javascript"; oScript.src = sUrl; document.getElementsByTagName('head')[0].appendChild(oScript); } createJs('jsonp.js?callback=box'); function box(json){ alert(json.name); }
2、Hash(url地址中#后面的东西)
--Hash的变动页面不会刷新 url中?后面的叫search:search的改变是会刷新页面的;所以search不能做跨域通信; // 利用hash,场景是当前页面 A 通过iframe或frame嵌入了跨域的页面 B,跨域给B发消息 // 在A中伪代码如下: var B = document.getElementsByTagName('iframe'); B.src = B.src + '#' + 'data'; // 在B中的伪代码如下 window.onhashchange = function () { var data = window.location.hash; }; **跨域给B发消息: 先拿到B这个窗口的地址src,然后通过hash的方式后面发一段字符串,这个字符串可以是通过 完整的json,最后通过json.stringify()把json转成字符串发给B,你是发出去了,B能不能接收 到,B在自己的代码中增加一个window.onhashchange,这个事件是用来监听你当前页面的hash有 没有改变。之前的页面是src,现在的页面加一个hash,所以对B来说,你的url的hash变化了, 就可以拿到了。拿到了以后通过window.location.hash就能拿到hash的具体内容。 window.location.hash可不是拿到一个,如果hash后面等于data除了A发送过来的东西还有别的 拼接,回来要特殊处理一下。
3、postMessage(html5新增加的处理跨域通信的)
同源策略的目标就是限制跨域通信,但是实际业务中又需要跨域通信; html5中出现了这个标准postMessage,用这个实现跨域通信; // 窗口A(http:A.com)向跨域的窗口B(http:B.com)发送信息 Bwindow.postMessage('data', 'http://B.com'); // 在窗口B中监听 Awindow.addEventListener('message', function (event) { console.log(event.origin); console.log(event.source); console.log(event.data); }, false); **怎么发送: 在A窗口,给谁发送,要选中哪个窗口,调postMessage这个API,第一个参数是发送的数据部分, 这里推荐使用字符串格式;第二个是接收方那个源,*是可以给任何窗口发送(很多窗口都能接收 到你的信息,这个是不安全的),推荐的做法是加上一个源; **发送对方怎么接受: B窗口要做哪些事情呢? 就是要监听message事件, window.addEventListener('message',响应函数,true/false指定捕获还是冒泡); 要拿的就是下面这三个参数: //来判断发送者的源,在你的响应程序中,你要选择性的接收;比如我只接收来自A.com的 信息,其他的一律不接收,那么就通过event.origin这个属性来判断 console.log(event.origin); console.log(event.source);//引用A窗口的对象 console.log(event.data);//发送的消息通过event.data拿到数据
4、WebSocket(不受同源策略限制的,拿来跨域通信正合适)
【参考资料】
1.声明一个webSocket对象,这个地方有两种,ws、wss区别一个加密一个非加密,
后面指向服务器的一个地址,这样就建立了相当于JS一个对象来管理这个链接。
var ws = new WebSocket(' wss://echo.websocket.org');
2.请求发送出去
1.声明一个webSocket对象,这个地方有两种,ws、wss区别一个加密一个非加密, 后面指向服务器的一个地址,这样就建立了相当于JS一个对象来管理这个链接。 var ws = new WebSocket('wss://echo.websocket.org'); 2.请求发送出去 ws.onopen = function (evt) { console.log('Connection open ...'); ws.send('Hello WebSockets!'); }; 3.对方给消息怎么接收,通过这个参数的data来拿到 ws.onmessage = function (evt) { console.log('Received Message: ', evt.data); ws.close(); }; 4.最后这个链接不用了,中断了,监听onclose来确定是不是关闭了 ws.onclose = function (evt) { console.log('Connection closed.'); };
5、CORS(Ajax一个变种,fetch实现CORS通信的--新出的通信标准,可以理解为支持跨域通信的Ajax)
【参考资料】
Ajax是不能发送跨域通信的,浏览器在识别你用Ajax发送了一个跨域请求的时候,它会在你 http头中加一个orgin,来允许跨域通信。如果不加这个头,就是一个普通的Ajax,遇到跨域通信, 浏览器就会拦截了(非法的不允许请求)。 // url(必选),options(可选),then就是回调成功,回调类似ES6的promise的写法; catch就是捕获错误。 fetch('/some/url/', { method: 'get', }).then(function (response) { }).catch(function (err) { // 出错了,等价于 then 的第二个参数,但这样更好用更直观 }); *CROS为什么就能支持跨域的这种通信? 浏览器会拦截ajax请求,如果它觉得这个ajax请求是跨域的,它会在http请求中,加一个origin