[深入15] WebSocket

2021-08-18  本文已影响0人  woow_wu7

导航

[深入01] 执行上下文
[深入02] 原型链
[深入03] 继承
[深入04] 事件循环
[深入05] 柯里化 偏函数 函数记忆
[深入06] 隐式转换 和 运算符
[深入07] 浏览器缓存机制(http缓存机制)
[深入08] 前端安全
[深入09] 深浅拷贝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模块化
[深入13] 观察者模式 发布订阅模式 双向数据绑定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手写Promise
[深入20] 手写函数

[react] Hooks

[部署01] Nginx
[部署02] Docker 部署vue项目
[部署03] gitlab-CI

[源码-webpack01-前置知识] AST抽象语法树
[源码-webpack02-前置知识] Tapable
[源码-webpack03] 手写webpack - compiler简单编译流程
[源码] Redux React-Redux01
[源码] axios
[源码] vuex
[源码-vue01] data响应式 和 初始化渲染
[源码-vue02] computed 响应式 - 初始化,访问,更新过程

前置知识

一些单词

specify:指定
stable:稳定的
amount:合计
optional:可选的 
optional object:可选对象
ordinary:普通的
omitted:省略的
broadcast:广播
outdated:过时的

NRM - nrm

(1) install
npm install -g nrm


(2) useage
nrm [options] [command] 

options
-h,--help //----------------------------------- help
-V,--version //-------------------------------- version number

commonds
nrm ls //------------------------------------------- 列出所有源
nrm use <registry> //------------------------------- 使用具体哪个源
nrm add <registry> <url> [home] //------------------ 添加源,(1) registry是源的名字,可以随便取 (2) url源地址
nrm del <registry> //------------------------------- 删除源
nrm test [registry] // ----------------------------- 测速,返回响应的时间

NVM - nvm

[图片上传失败...(image-6a3933-1629296489782)]

useage

nvm use <version> [arch] //------------------ 使用哪个版本的node,(arch表示32位或64位,非必须)
mvm list [available] // --------------------- 展示可用的node版本列表,(available表示有效,非必须)
nvm install <version> [arch] // ------------- 安装指定的node版本,version表示具体的版本号
nvm uninstall <version>
----
查看全局安装的包:----------------- npm ls -g --depth=0
查看全局安装的包:----------------- npm list -g --depth=0 // ls 和 list 都可以
卸载本地全局安装包:--------------- npm uninstall -g xxxx
查看需要更新的全局包:------------- npm outdated -g --depth=0 // outdated是过时的意思

npm info xxxx // ------------------------------ 远程包的信息
npm info xxxx version // ---------------------- 远程最新的版本号
npm info xxxx versions // --------------------- 远程所有版本号

window.postMessage 跨域通信

(一)
otherWindow.postMessage(message, targetOrigin, [transfer]) 跨域通信

(1) otherWindow
- otherWindow指的是其他窗口的一个引用
1. iframe 的 contentWindow 属性
2. window.open() 返回的一个窗口对象
3. 命名过或数值索引的 window.frames
4. 两个窗口之间
  - a -> b,otherWindow是b窗口
  - b -> a,otherWindow是a窗口,即 ( top ) 或者 ( parent )

(2) message
- message指发送给其他窗口的数据
- message会被序列化,所以无需自己序列化

(3) targetOrigin     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- targetOrigin:设置目标窗口的源(协议域名端口组成的字符串),指定哪些窗口能 ( 接收 ) 到消息事件
- 在 ( 发消息 ) 的时候,如果( 目标窗口 ) 的 ( 协议,域名,端口) 任意一项不满足 targetOrigin 提供的值,消息就不会发送
- 三者要全部匹配才会发送
- targetOrigin的值可以是 (  *  ) 号,表示所有窗口都能接收到消息

(4) transfer
- transfer 是一串和message同时传递的 Transferable 对象
- 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权



发消息:--------------- otherWindow.postMessage(message, targetOrigin, [transfer])
收消息:--------------- window.addEventListener('message', (data) => {console.log(data.data, data.origin)}, false)
注意:----------------- 通过 ( targetOrigin - 验证接收方 ) 和 ( data.origin - 验证发送方 ) 来精确通信


- data.origin 和 data.source 和 data.data
- 在接收端的监听函数中,注意 origin 和 source
- origin: ------------- 发送方的协议,域名,端口组成的字符串
- source:------------- 发送方窗口对象的引用
- data:--------------- 接收到的数据
window.addEventListener("message", receiveMessage, false); // 接收消息的tab标签页面监听message事件
function receiveMessage(event) {
  // For Chrome, the origin property is in the event.originalEvent
  // object. 
  // 这里不准确,chrome没有这个属性
  // var origin = event.origin || event.originalEvent.origin; 
  var origin = event.origin
  if (origin !== "http://example.org:8080")
    return;
    // ...
}


(二)
注意事项:
- 使用postMessage将数据发送到其他窗口时,始终要指定精确的目标origin,而不是使用 *
- 使用 origin 和 source 验证 ( 发件人 ) 的身份


(三)
实例:

--------------
a页面
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="a-open">点击,打开b页面</div>
  <div id="a-send">点击,发送消息,a->b</div>
  <script>
    const aOpen = document.getElementById('a-open')
    const aSend = document.getElementById('a-send')
    var a = null
    aOpen.addEventListener('click', () => a = window.open('http://127.0.0.1:5500/b.html'), false)
    aSend.addEventListener('click', () => a.postMessage('this message is a to b', 'http://127.0.0.1:5500'), false)
    // 注意:
    // 1. a.postMessage只有在目标页面(b页面)的页面加载完成时才能发送
    // 2. a.postMessage的第二个参数,表示targetOrigin目标源,即目标窗口的协议域名端口组成的字符串
    // 3. targetOrigin设置过后,只有目标窗口完全符合targetOrigin字符串的值才能接收到消息
  </script>
</body>
</html>


---------------
b页面
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>b页面</div>
  <script>
    window.addEventListener('message', (data) => { // ----- 监听message事件
      console.log(data)
    }, false)
  </script>
</body>
</html>

[图片上传失败...(image-e38cd8-1629296489782)]

websocket概述

[图片上传失败...(image-1b8889-1629296489782)]

WebSocket 客户端api

new WebSocket(url)

webSocket.readyState

CONNECTING:0 --------------- 表示正在连接
OPEN: 1 --------------------- 表示连接成功,可以通信了
CLOSING:2 ------------------ 表示连接正在关闭
CLOSED:3 ------------------- 表示连接已经关闭,或者连接打开失败

webSocket.onopen

webSocket.onclose

<font color=red>webSocket.onmessage</font>

ws.onmessage = function(event) {
  var data = event.data;
  // 处理数据
};

ws.addEventListener("message", function(event) {
  var data = event.data;
  // 处理数据
});


----------


ws.onmessage = function(event){
  if(typeof event.data === String) {
    console.log("Received data string");
  }

  if(event.data instanceof ArrayBuffer){
    var buffer = event.data;
    console.log("Received arraybuffer");
  }
}

<font color=red>webSocket.send()</font>

webSocket.bufferedAmount

webSocket.onerror

使用 websocket 和 nodejs-websocket 简单聊天室

客户端:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="text" id="name-input">
  <button id="name-button">创建名字</button>
  <input type="text" id="input">
  <button id="button">发送消息</button>
  <script>
    const inputDom = document.getElementById('input')
    const button = document.getElementById('button')
    const nameInput = document.getElementById('name-input')
    const nameButton = document.getElementById('name-button')
    const ws = new WebSocket('ws://localhost:5555') 
    // ----------------------------------------------------- 生成websocket实例对象
    // ----------------------------------------------------- 参数是url
    // ----------------------------------------------------- 注意:协议是 (ws:// ) 或者 (wss:// 加密协议)
    ws.onopen = function() { // ---------------------------- onopen:连接成功后的回调
      // ws.send('客服端 => 发送给服务端的消息字符串') // -- send():向服务端发送消息
      nameButton.addEventListener('click', () => {
        nameButton.setAttribute('disabled', 'disabled')
        ws.send(JSON.stringify({
          type: 'name',
          value: nameInput.value
        }))
      }, false)
      button.addEventListener('click', () => {
        ws.send(JSON.stringify({
          type: 'chat',
          value: inputDom.value,
        }))
      }, false)
    }
    ws.onmessage = function(e) { // --------------------------- onmessage:收到服务端返回数据时触发的回调
      const p = document.createElement('p')
      p.innerHTML = e.data
      document.body.appendChild(p)
    }
/*
    ws.addEventListener('open', connectedCallback, false)
    function connectedCallback() {
      ws.send('客服端 => 发送给服务端的消息字符串')
    }
    ws.onopen = function() {
      ws.send('客服端 => 发送给服务端的消息字符串')
    }
    ws.onmessage = function(e) {
      console.log(e.data)
    }
*/
  </script>
</body>
</html>


服务端:
const ws = require('nodejs-websocket')

const server = ws.createServer(function(conn) {
  console.log("New connection")
  conn.on("text", function (str) { // ------------------------ 客户端发来的数据是text类型时触发
       console.log("Received "+str)
    // conn.sendText(str)
    const data = JSON.parse(str)

    switch(data.type) {
      case 'name':
          conn.nickname = data.value;
          broadcast(data.value + '加入了房间');
          break;
      case 'chat':
          console.log(data.value, 'data.value');
          broadcast(data.value);
          break;
      default:
        break;
    }
  })
  function broadcast(str) { // --------------------------------------- broadcast:广播
    server.connections.forEach((conn) => {
      conn.sendText(str)
    })
  }
    conn.on("close", function (code, reason) { // --------------------- 关闭连接时触发
    console.log("Connection closed")
    broadcast(conn.nickname + '离开了房间')
  })
  // conn.send('服务端 => 发给客服端的消息')
  conn.on('error', (err) => { // -------------------------------------- 处理错误
    console.log(err)
  })
})
server.listen(5555, () => console.log('server runing')) // ------------- 监听端口

[图片上传失败...(image-cb30b0-1629296489782)]

资料

https://juejin.im/post/6844903519649005576
阮一峰 http://www.ruanyifeng.com/blog/2017/05/websocket.html
nvm 和 nrm https://juejin.im/post/6844903799530733582
nrm官网:https://github.com/Pana/nrm
nrn安装后输入命令报错:https://blog.csdn.net/ougexingfuba/article/details/104056327
nodejs-websocket:https://github.com/sitegui/nodejs-websocket
otherWindow.postMessage:https://juejin.im/entry/6844903444109606925

上一篇 下一篇

猜你喜欢

热点阅读