小程序websocket开发指南( 四 )

由于需要监听?websocket?的连接与断开,因此需要新生成一个computed属性?newGlobalWebsocket?,直接返回全局的?globalWebsocket?对象,这样才能watch到它的变化,并且在重新监听的时候需要控制好条件,只有?globalWebsocket?对象socketTask真正发生改变的时候才进行重新监听逻辑,否则会收到重复的消息 。
问题总结

  1. 直接引入google官方Protobuf库(protobuf.js)将json => pb,在开发者工具能正常使用,真机却报错:

小程序websocket开发指南

文章插图
 

小程序websocket开发指南

文章插图
 
【小程序websocket开发指南】原因是protobufjs 代码里面有用到 Function() {} 来执行一段代码,在小程序中Function 和 eval 相关的动态执行代码方式都给屏蔽了,是不允许开发者使用的,导致这个库不能正常使用 。
解决办法:搜了一圈github,找到有人专门针对这个问题,修改了dcodeIO 的protobuf.js部分实现方式,写了一个能在小程序中运行的 protobuf.js。
  1. ?ArrayBuffer? vs ?Unit8Array? 到底是个什么关系??!
  • 受小程序框架、protobuf.js工具以及Frontier系统限制,发送消息和接收消息的格式如下

小程序websocket开发指南

文章插图
 

小程序websocket开发指南

文章插图
 
可以看到:
  • 发送消息经过protobuf.js编码后的消息是?Unit8Array?格式的
  • 接收到的服务器原始消息是?ArrayBuffer?格式的
上文介绍了?TyedArray?和?ArrayBuffer?的区别,?Unit8Array?是?TypedArray?对象的一种类型,用来表示?ArrayBuffer?的视图,用来读写?ArrayBuffer?,要访问?ArrayBuffer?的底层对象,必须使用?Unit8Array?的buffer属性 。
  • 一开始跟服务端调websocket的连通性,发现用?AwesomeMessage.decode?解析服务端消息会解析失败:

小程序websocket开发指南

文章插图
 
const msg = xxx; // ArrayBuffer类型const res = AwesomeMessage.decode(msg); // 直接解析ArrayBuffer会报错const res = AwesomeMessage.decode(new Uint8Array(msg)); // ArrayBuffer => Unit8Array => decode => JSON原因是原始msg是?ArrayBuffer?类型,protobuf.js在解码的时候限制了类型是?TypedArray?类型,否则解析失败,因此需要将其转换为?TypedArray?对象,选择?Uint8Array?子类型,才能解析成前端能读取的json对象 。
  • 在开发者工具调通协议后,转到真机,发现后端解析不了前端发的消息:

小程序websocket开发指南

文章插图
 

小程序websocket开发指南

文章插图
 
【开发者工具抓包消息】
小程序websocket开发指南

文章插图
 
【真机抓包消息】抓包发现在开发者工具发送的消息是二进制(Binary)类型的,真机却是文本(Text)类型,这就很奇怪了,仔细翻了下小程序文档:
小程序websocket开发指南

文章插图
 
小程序框架对发送的消息类型进行了限制,只能是string(Text)或arraybuffer(Binary)类型的,真机为啥被转成了text类型呢,首先肯定不是主动发送的string类型,一种可能就是发送的消息不是arraybuffer类型,默认被转成了string 。看了下代码:
const encodeMsg = (msg) => {const message = AwesomeMessage.create(msg);const array = AwesomeMessage.encode(message).finish();// unit8Arrayreturn array;};发现发送的类型直接是?Unit8Array?,开发者工具没有对其进行转换,这个数据是能直接被服务端解析的,然而在真机被转换成了String,导致服务端解析不了,更改代码,将?Unit8Array?转换成?ArrayBuffer?,问题得到解决,在真机和开发者工具都正常:
const encodeMsg = (msg) => {const message = AwesomeMessage.create(msg);const array = AwesomeMessage.encode(message).finish();  console.log('加密后即将发送的消息', array);// unit8Array => ArrayBuffer,只支持ArrayBufferreturn array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)};其实还发现一个现象:
小程序websocket开发指南

文章插图
 
即收到的服务端原始消息最外层是?ArrayBuffer?类型的,解密后的业务数据payload却是?Unit8Array?类型的,结合发送消息时encdoe后的类型也是?Unit8Array?类型,得出如下结论:


推荐阅读