web 通信类

1、什么是同源策略级限制?

2、前后端如何通信?

3、如何创建ajax?

4、跨域通信的几种方式?

什么是同源策略限制:

先解释什么是源,然后再解释

源:协议,域名,端口  三个有其中一个不一样,就是不同源,

就是不是同一个源不能操作另外一个源的东西

主要限制在以下三个方面:

cookie、localstorage 和indexDB无法读取

DOM无法获得

ajax请求不能发送

前后端如何通信

Ajax(同源策略限制)  WebSocket(不受同源策略限制)  CORS(支持同源也支持不同源)

如何创建ajax?

XMLHttpRequest对象的工作流程

兼容性处理

事件触发的条件

事件的触发顺序

创建对象xhr ->open() ->send() 

响应 xhr.onload = function(){}

/**
* [json 实现ajax的json]
* @param {[type]} options [description]
* @return {[type]} [description]
*/
util.json = function (options) {
var opt = {
url: '',
type: 'get',
data: {},
success: function () {},
error: function () {},
};
util.extend(opt, options);
if (opt.url) {
var xhr = XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
var data = opt.data,
url = opt.url,
type = opt.type.toUpperCase(),
dataArr = [];
for (var k in data) {
dataArr.push(k + '=' + data[k]);
}
if (type === 'GET') {
url = url + '?' + dataArr.join('&');
xhr.open(type, url.replace(/?$/g, ''), true);
xhr.send();
}
if (type === 'POST') {
xhr.open(type, url, true);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(dataArr.join('&'));
}
xhr.onload = function () {
if (xhr.status === 200 || xhr.status === 304) {
var res;
if (opt.success && opt.success instanceof Function) {
res = xhr.responseText;
if (typeof res ==== 'string') {
res = JSON.parse(res);
opt.success.call(xhr, res);
}
}
} else {
if (opt.error && opt.error instanceof Function) {
opt.error.call(xhr, res);
}
}
};
}
};

跨域通信的几种方式

JSONP:img中的src,link的href,script 中的src这三个都不符合同源策略,但是它们都能跨域获取资源,jsonp就是利用script的这个特点来实现跨域获取数据的

它只支持GET请求而不支持POST等其它类型的HTTP请求

jsonp是由两部份组成的,回调函数和数据

Hash: url#后面的就是hash,hash改变,页面不刷新 缺点:另外由于URL大小的限制,支持传递的数据量也不大。

postMessage:

优缺点:

 优点:方便,安全,有效的解决了跨域问题

 缺点:万恶的资本主义,ie8+才支持,而且ie8+<ie10只支持iframe的方式。

WebSocket:是一种网络协议,与http的差异是:http仅当客户端向服务器发送请求的时候,服务器才会向客户端发送信息,而websocket服务器可以主动向客户端发送信息,客户端也可以向服务器主动发送信息。此协议没有同源限制,协议标识符是 ws,加密后的是wss 详细见http://www.ruanyifeng.com/blog/2017/05/websocket.html

CORS:

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制

CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

 浏览器发出CROS请求,就是在头信息增加一个origin字段,这个字段用来说明本次请求来自哪个源,服务器会根据这个源绝对是否同意这次请求

jsonp

    <div class="left" id="left">left</div>
<div class="right">right</div>
</section>
<script type="text/javascript" charset="utf-8">
document.getElementById('left').onclick = function () {
var script = document.createElement('script');
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script,document.body.firstChild)
}
function handleResponse(res){
console.log('res',res)
}
</script>

hash

原理是利用location.hash来进行传值。

假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息。

1) cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面

2) cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据

3) 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值

注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe

代码如下:

先是a.com下的文件cs1.html文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function startRequest(){
 var ifr = document.createElement('iframe');
 ifr.style.display = 'none';
 document.body.appendChild(ifr);
}
 
function checkHash() {
 try {
  var data = location.hash ? location.hash.substring(1) : '';
  if (console.log) {
   console.log('Now the data is '+data);
  }
 } catch(e) {};
}
setInterval(checkHash, 2000);

cnblogs.com域名下的cs2.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//模拟一个简单的参数处理操作
switch(location.hash){
 case '#paramdo':
  callBack();
  break;
 case '#paramset':
  //do something……
  break;
}
 
function callBack(){
 try {
  parent.location.hash = 'somedata';
 } catch (e) {
  // ie、chrome的安全机制无法修改parent.location.hash,
  // 所以要利用一个中间的cnblogs域下的代理iframe
  var ifrproxy = document.createElement('iframe');
  ifrproxy.style.display = 'none';
  ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata'; // 注意该文件在"a.com"域下
  document.body.appendChild(ifrproxy);
 }
}

a.com下的域名cs3.html

1
2
//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

// 利用hash,场景是当前页面 A 通过iframe或frame嵌入了跨域的页面 B
/

postMessage

postMessage实现跨域

   语法:window.postMessage(msg,targetOrigin)

    window: 指目标窗口,可能是window.frames属性的成员或者由window.open方法创建的窗口

    message:要发送的消息,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果

    targetOrigin:“目标域“,包括:协议、主机名、端口号。若指定为”*“,则表示可以传递给任意窗口,指定为”/“,则表示和当前窗口的同源窗口。

    获取postMessage传来的消息:为页面添加onmessage事件

1 window.addEventListener('message',function(e) {
2     
3 }

    onmessage事件接受一个参数e,它是一个event对象。

    e的几个重要属性:

      1、data:postMessage传递过来的msg

      2、发送消息的窗口对象

      3、origin:发送消息窗口的源(协议+主机+端口号)

     来写一个简单的demo:

     http://source.com/source.html用来发送数据:

1 <iframe id="iframe" src="http://target.com/target.html"></iframe>
2 <input id="msg" type="text" placeholder="请输入要发送的消息">
3 <button id="send">发送</button>
复制代码
1 window.onload =function() {
2     document.getElementById('send').onclick = function() {
3     var msg = document.getElementById('msg').value;
4     var iframeWindow = document.getElementById('iframe').contentWindow;
5     iframeWindow.postMessage(msg,"http://target.com/target.html");
6     }
7 }
复制代码

     http://target.com/target.html用来接收数据:  

1 <div>
2     <h2>target.html,以下是接收到的消息:</h2>
3     <section id="msg">
4         
5     </section>
6 </div>
复制代码
 1 window.onload = function() {
 2 
 3     if(window.addEventListener){
 4         window.addEventListener("message", handleMessage, false);
 5     }
 6     else{
 7         window.attachEvent("onmessage", handleMessage);
 8     }  
 9 
10     function handleMessage(event) {
11         event = event || window.event;
12 
13         if(event.origin === 'http://source.com') {
14             document.getElementById('msg').innerHTML = event.data;
15         }
16     }
17 }
复制代码

// Websocket【参考资料】http://www.ruanyifeng.com/blog/2017/05/websocket.html

var ws = new WebSocket('wss://echo.websocket.org');

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.');
};

// CORS【参考资料】http://www.ruanyifeng.com/blog/2016/04/cors.html
// url(必选),options(可选)
fetch('/some/url/', {
method: 'get',
}).then(function (response) {

}).catch(function (err) {
// 出错了,等价于 then 的第二个参数,但这样更好用更直观
});

原文地址:https://www.cnblogs.com/liangshuang/p/8495449.html