- 前后端通信方式
- 如何创建Ajax
- 什么是同源策略?同源策略的目的?非同源的限制范围?
- 解决跨域的几种方式
前后端通信的方式:
- Ajax
- WebScocket
- CROS
如何创建Ajax
原理: 通过XMLHttpRequest对象向服务器发送异步请求,从服务器获得数据,然后操作DOM更新数据。XMLHttpRequest对象是ajax的基础
XMLHttpReques对象的属性有:
-
-
- onreadystatechange: 每当readyState状态改变时,就会触发该事件
-
-
-
- readyState
-
该属性存有XMLHttpRequest的状态。从0到4放生变化:
-
-
-
-
- 0(请求未初始化):XMLHttpRequest对象还没有完成初始化
- 1(服务器连接已建立):XMLHttpRequest对象开始发送请求
- 2(请求已接收):XMLHttpRequest对象请求发送完成
- 3(请求处理中):XMLHttpRequest对象开始读取服务器的响应,正在解析接收到的内容
- 4(请求完成,且响应已就绪):XMLHttpRequest对象读取服务器响应结束
-
- status: 从服务器返回的HTTP状态码
-
-
-
-
- responseText:从服务器返回字符串形式的响应数据
-
-
-
- responseXML: 从服务器返回 XML 形式的响应数据
-
封装ajax代码如下:
function ajax(options){ //默认参数 var defaults = { url: '', type: 'GET', data:{}, success: function(){}, error: function(){} }; //覆盖默认参数 for(var key in options){ defaults[key] = options[key]; } if(defaults.url){ var xmlhttp = XMLHttpRequest? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');//IE6 不支持XMLHttpRequest //参数 var dataArr = []; for(var k in data){ dataArr.push(k + '=' + data[k]); } if(defaults.type.toUpperCase() === 'GET'){//GET方法 var url = defaults.url + '?' + dataArr.join('&'); xmlhttp.open(defaults.type,url,true); xmlhttp.send(); //将请求发送到服务器 }else if(defaults.type.toUpperCase() === 'POST'){//POST 方法 xmlhttp.open(defaults.type,defaults.url,true); xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xmlhttp.send(dataArr.join('&')); } xmlhttp.onreadystatechange = function(){ if(xmlhttp.readyState == 4 && (xmlhttp.status == 200 || xmlhttp.status == 304)){ if(defaults.success && defaults.success instanceof Function){ //接收到相应数据 var data = xmlhttp.responseText; defaults.success(data); } }else{ if(defaults.error && defaults.error instanceof Function){ defaults.error(); } } } } }
调用方式:
ajax({ url: '/url', type:'POST', data:{ id: 'id1', name:'name' }, success: function(data){ //成功后执行的代码 console.log('success') }, error: function(status){ //失败后执行的代码 } });
同源策略
1.什么是同源策略
先了解一下什么是同源,所谓的“同源”指的是三个相同:
-
-
- 协议相同
- 域名相同
- 端口相同
-
只有这三个都相同才是同源,否则为非同源。
同源策略:指的是浏览器对不同源的脚本或者文本的访问进行的限制
2. 目的
为了保护用户信息安全,防止恶意的网站窃取数据
3.限制范围
非同源之间有如下行为都是受到限制的:
-
-
- cookie、localStorage无法读取
- DOM 无法获取
- AJAX 请求不能发送
-
这些限制是必要的,但是有时候我们合理的用途也受到了影响。下面将介绍,如何避免上面三种限制
解决跨域的方案
为了解决上面三种情况不再受到限制,我们采用了不同跨域的解决方案
一、Cookie
我们知道只同源的网页Cookie才能共享。那么怎么才能获取到非同源网站的cookie呢?可以通过设置document.domain来共享cookie
方案: 设置document.domain为一级域名
该方案的适用条件:两个网页一级域名相同,只是二级域名不同的情况
举例说明:
网页A (http://btp.example.com/a.html)中设置了一个cookie
document.cookie = "number=1";
网页B (http://test.example.com/b.html)中想获取到网页A中设置的cookie,A和B的主域名相同二级域名不同,是非同源的。此时,我们可以设置document.domain 为一级域名exanple.com,即:
document.domain = 'example.com';
这样,在网页B中就可以读取到网页A中设置的cookie了。
var allCookie = document.cookie; //'number=1'
二、DOM元素获取
适用条件: iframe页面,父窗口和子窗口两个页面的一级域名相同,只是二级域名不同的情况
方案:设置document.domain为一级域名
举例说明:
父页面 A (http://btp.example.com/a.html):
<div id="parent">parent</div> <iframe id="iframe" src="http://test.example.com/b.html" height="200" width="200"></iframe> <script> window.onload = function(){ var _iframe = document.getElementById('iframe').contentWindow; var div = _iframe.document.getElementById('child'); } </script>
子页面 B(http://test.example.com/b.html):
<div id="child">child</div> <script> window.onload = function(){ var _iframe = window.parent; var _div = _iframe.document.getElementById('parent'); } </script>
由于跨域导致浏览器会报错。只需要设置 在页面那中设置 document.domain = 'example.com’,就可以拿到DOM元素了
三、通信
对于主域名相同二级域名不同的情况,我们可以设置document.domain属性来解决跨域通行。那么对于完全不同源的网站,可以使用以下方法来解决:
1. hash
方案:把信息放到URL的#号后面,然后通过监听haschange事件
适用条件:A 通过iframe嵌入(或frame嵌入了跨域的)页面 B
举例说明:
父窗口把数据data写到子窗口url的#号后面:
<div id="parent">parent</div> <iframe id="iframe" src="http://example.com/b.html" height="200" width="200"></iframe> <script>
var B = document.getElementById('iframe').src;
B.src = B.src + '#' + data;
</script>
子窗口监听haschange事件得到通知:
window.onhaschange = function(){ var message = window.location.hash; }
子窗口也同样可以把数据传给父窗口
parent.location.href = parent.location.href + '#' + data
2. postMessage
h5为了解决跨域通信问题,引入了跨域通信API,这个API增加了一个window.postMessage方法,该方法允许跨域通信。
方案:数据通过postMessage方法发送消息,然后通过监听message来获取数据
适用条件:A 通过iframe嵌入(或frame嵌入了跨域)页面 B
举例说明:
父窗口A(http://aa.com/a.html)向子窗口B(http://example.com/b.html)发送消息 : Bwindow.postMessage(message,origin)
<div id="parent">parent</div> <iframe id="iframe" src="http://example.com/b.html" height="200" width="200"></iframe> <script> window.onload = function(){ var data ={ name:'test', age:8 }; document.getElementById('iframe').contentWindow.postMessage(JSON.stringify(data),'http://example.com'); } </script>
注: postMessage的写法,postMessage之前是你要通行的window对象(也就是你要向谁通信),上例子中是向子窗口B发送消息。
postMessage方法中接收两个参数:
* 第一个参数:传递的数据(推荐使用字符串格式)
* 第二个参数:目标窗口的源,协议+主机+端口号。如果设置为“*”,表示可以传递任意窗口
子窗口B接收数据:
window.addEventListener('message',function(event){ console.log(event.source); //发送消息的窗口window对象 A窗口的window console.log(event.origin); //发送消息的窗口的源 http://aa.com console.log(event.data); //消息内容 {name:'test',age:8}; },false);
子窗口通过event.source属性引用父窗口,可以向父窗口发送消息
window.addEventListener('message',function(event){ event.source.postMessage('hello',event.origin) },false);
四、AJAX
AJAX只能发送给同源的网址,否则会报错。解决ajax跨域的方案如下:
1. JSONP(只能发GET请求)
JSONP基本思想:网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策的限制;服务器收到请求后,将数据放到指定名字的回调函数中传回来
具体步骤:
1.动态插入<script>元素,由它向跨源网址发出请求
2. 该请求的url有一个callback参数,用来指定回调函数的名字,该回调函数需要在页面中定义好。
3. 服务器收到请求后,会将数据放到指定的回调函数中作为参数返回。
具体代码实现:
function createScript(src){ var script = document.createElement('script'); script.setAttribute('type','text/javascript'); script.src = src; document.getElementsByTagName('head')[0].appendChild(script); }; window.onload = function(){ var url = 'http://example.com/ip?callback=foo'; createScript(url); }; //定义foo函数 function foo(data){ console.log('success :' + data); }
服务器收到请求后,会将数据放在回调函数foo的参数位置返回
foo({success:true,data:[]})
这样,我们就可以在定义的foo函数中读取到返回的数据了
2. CORS
CROS是一种访问机制,全称“跨域资源共享”(Cross-Origin Resource Sharing)。通过在服务器端设置响应头,把跨域的域名添加到Access-Control-Allow-Origin即可
具体实现 http://www.ruanyifeng.com/blog/2016/04/cors.html