课程思维导图
Q:什么是跨域通信?
一个域下的文档或脚本试图去请求另一个域下的资源
Q:什么是同源策略?
- 同源:协议、域名、端口
- 非同源的限制:
- cookie、localStorage、indexDB无法读取
- DOM无法获得
- Ajax 请求不能发送
Q:前后端通信有哪些?
- Ajax : 同源下的通信方式
- WebSocket:不受同源策略限制
- CORS:支持跨域通信,也支持同源通信
Q:如何创建创建Ajax?
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
// 完整版function ajax(opt) { if(!opt.url) return; 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); } } };}// 简易版,只考虑GET方式var xhr = new XMLHttpRequest();var url = '/test';xhr.open('GET', url, true);/** * 监听服务端跟客户端通信的过程和进度 */xhr.onreadystatechange = function () { /** * 每当 readyState 改变时,就会触发 onreadystatechange 事件。 * 4: 请求已完成,且响应已就绪 */ if (xhr.readyState === 4) { // 200 成功 if (xhr.status === 200) { console.log(xhr); } else { console.log('error'); } }}xhr.send();//发起客户端请求
Q:跨域解决方案有哪些?
方案1:document.domain:
- 场景:两个网页一级域名相同,只是二级域名不同
- 方案:浏览器允许通过设置document.domain共享 Cookie。这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法
方案2:通过jsonp跨域
12345678910111213141516
// 客户端实现:<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 传参并指定回调执行函数为onBack script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack'; document.head.appendChild(script); // 回调执行函数 function onBack(res) { alert(JSON.stringify(res)); }</script>// 服务端(返回时即执行全局函数)onBack({"status": true, "user": "admin"})
方案三:location.hash
场景:当前页面 A 通过iframe或frame嵌入了跨域的页面 B
1234567
// 在A中伪代码如下:var B = document.getElementsByTagName('iframe');B.src = B.src + '#' + 'data';// 在B中的伪代码如下:window.onhashchange = function () { var data = window.location.hash;};
方案四:postMessage
HTML5引入跨文档通信API,这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源
123456789
// 例如,窗口A(http:A.com)向跨域的窗口B(http:B.com)发送信息var popup = window.open('http://B.com', 'title');popup.postMessage('Hello World!', 'http://B.com');// 在窗口B中监听window.addEventListener('message', function (event) { console.log(event.origin); // 消息发向的网址 console.log(event.source); // 发送消息的窗口 console.log(event.data); // 消息内容}, false);
方案五:WebSocket
123456789101112
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
123456
fetch('/some/url/', { method: 'get',}).then(function (response) {}).catch(function (err) { // 出错了,等价于 then 的第二个参数,但这样更好用更直观});