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:
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‘ ; ifr.src = ‘http://www.cnblogs.com/lab/cscript/cs2.html#paramdo‘ ; 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 的第二个参数,但这样更好用更直观
?????});
web 通信类
原文地址:https://www.cnblogs.com/liangshuang/p/8495449.html