前端基础-通讯

245 阅读6分钟

1:什么是同源策略及限制

1-1:什么是同源?

如果两个URL的协议、域名和端口号都相同,我们就称这两个URL同源。

1-2:什么是同源策略

浏览器默认两个相同的源之间是可以相互访问资源和操作DOM的。而不同的源之间不可以做到这一点,若想要相互访问资源或者操作DOM,那么需要增加一些安全策略的制约,我们把这称为同源策略。

1-3:不可以相互访问资源和操作DOM分别都是指什么?

可以分为三个部分:DOM层面、数据层面、网络层面

1-3-1- DOM层面

不同源的JS脚本不可以对当前站点的DOM对象进行读写操作 如,通过A服务器发来的JS脚本去修改B服务器中某个网页的HTML内容,是做不到的。

1-3-2- 数据层面

不同源的站点不可以读取当前站点的Cookie、IndexDB、LocalStorage等数据

1-3-2- 网络层面

限制通过http请求(GET、POST等)将某站点的数据发送给不同源的站点。反之,不可以通过http请求向不同源站点获取数据。

1-4、如果突破这三个层面的限制?

  • 读取数据和操作DOM用跨文档机制
  • 跨域请求用CORS机制
  • 引用第三方资源用CSP

同源策略限制

从一个源加载的文档或者脚本如何与来自另一个源的资源进行交互,这是一个用于隔离潜在恶意文件的关键的安全机制。

cookie、localStorage和indexDB无法读取

DOM无法获得

AJAX请求不能发送

2:前后端如何通讯

1. ajax

  浏览器发起请求,服务器返回数据,服务器不能主动返回数据,要实现实时数据交互只能是ajax轮询(让浏览器隔个几秒就发送一次请求,然后更新客户端显示。这种方式实际上浪费了大量流量并且对服务端造成了很大压力)。

2. websocket

websocket是HTML5出的东西(协议),是一种全双工通信机制,两端可以及时地互发事件,互发数据,相互通信,只需要浏览器和服务器建立一次连接,服务器就可以主动推送数据到浏览器实现实时数据更新。

原生 websocket 支持到IE11 ,实际开发中,有比较著名的两个库socket.io(推荐)(英文版中文版可能跟新不及时) 和 sockjs , 它们都对原始的API做了进一步封装和兼容IE,提供了更多功能,都分为客户端和服务端的实现,实际应用中,可以选择使用。

websocket  的实现需要后端搭建一个WebSocket服务器,但是如果想搭建一个WebSocket服务器就没有那么轻松了,因为WebSocket是一种新的通信协议,目前还是草案,没有成为标准,市场上也没有成熟的WebSocket服务器或者Library实现WebSocket协议,我们就必须自己动手写代码去解析和组装WebSocket的数据包。要这样完成一个WebSocket服务器,估计所有的人都想放弃,幸好的是市场上有几款比较好的开源库供我们使用,比如 PyWebSocket,WebSocket-Node, LibWebSockets等等,这些库文件已经实现了WebSocket数据包的封装和解析,我们可以调用这些接口,这在很大程度上减少了我们的工作量。

3:socket.io(推荐)

socket.io 是一个为实时应用提供跨平台实时通信的库。socket.io 旨在使实时应用在每个浏览器和移动设备上成为可能,模糊不同的传输机制之间的差异。
socket.io 的名字源于它使用了浏览器支持并采用的 HTML5 WebSocket 标准,因为并不是所有的浏览器都支持 WebSocket ,所以该库支持一系列降级功能:

  • Websocket
  • Adobe® Flash® Socket
  • AJAX long polling
  • AJAX multipart streaming
  • Forever Iframe
  • JSONP Polling

 

在大部分情境下,你都能通过这些功能选择与浏览器保持类似长连接的功能。

  • 优点:跨平台、兼容性好、具有降级功能、所有传输机制接口对外统一、自带心跳。
  • 缺点:要使用socket.io必须前后端都要用一套框架。
  • 适用于:考虑更多兼容性,后端可以使用基于socket.io的框架的情景。(常见服务端实现框架有node.js,Netty-socket.io)

3:如何创建ajax

Ajax的原理:

简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据

ajax过程:

3-1:创建 XMLHttpRequest 对象,也就是创建一个异步调用对象

3-2:创建一个新的 HTTP 请求,并指定该 HTTP 请求的方法、URL 及验证信息

3-3:设置响应 HTTP 请求状态变化的函数

3-4:发送 HTTP 请求

3-5:获取异步调用返回的数据

3-6:使用 JavaScript和 DOM 实现局部刷新

4:跨越通讯的几种方式

4-1:JSONP

支持跨域,本质是script标签不受同源策略的限制。只支持GET请求。

以下是功能比较完整的jsonp代码

var count = 0;
function noop () {}

function jsonp(url, opts, fn){
  if (!opts) opts = {};

  var prefix = opts.prefix || '__jp';
  var id = opts.name || (prefix + (count++));

  var param = opts.param || 'callback';
  var timeout = null != opts.timeout ? opts.timeout : 60000;
  var target = document.getElementsByTagName('script')[0] || document.head;
  var script;
  var timer;


  if (timeout) {
    timer = setTimeout(function(){
      cleanup();
      if (fn) fn(new Error('Timeout'));
    }, timeout);
  }

  function cleanup(){
    if (script.parentNode) script.parentNode.removeChild(script);
    window[id] = noop;
    if (timer) clearTimeout(timer);
  }

  function cancel(){
    if (window[id]) {
      cleanup();
    }
  }

  window[id] = function(data){
    cleanup();
    if (fn) fn(null, data);
  };

  url += (url.includes('?') ? '&' : '?') + param + '=' + encodeURIComponent(id);
  url = url.replace('?&', '?');

  script = document.createElement('script');
  script.src = url;
  target.parentNode.insertBefore(script, target);

  return cancel;
}

4-2:CORS

可以将其理解为支持跨域的Ajax。具体可以参考阮一峰老师的文章。

4-3:WebSocket

支持跨域。使用ws://(非加密)和wss://(加密)作为协议前缀。

4-4:图像PING

同样支持跨域,但是只支持GET请求并且无法得到返回结果。

(new Image()).src = 'http://xxx.cn?id=3'

4-5:Hash

用于页面A与其iframe中的跨域页面B进行通信,B也可以改变A的Hash。

// A页面
bPage.src  = bPage.src + '#' + data

// B页面
window.onhashchange = function () {
  const data = window.location.hash
}

4-6:postMessage

HTML5推出的新API。

// 父窗口
childWindow.postMessage('Hello World!',  'http://bbb.com')

// 子窗口
window.addEventListener('message', function (e) {
  e.origin // 父窗口的域名
  e.source // 父窗口的window对象
  e.data // 传输的数据
})

4-7:document.domain

适用于 Cookie 和 iframe 窗口。若两个网页一级域名相同,只是二级域名不同,则能通过设置相同的document.domain进行跨域通信。