当前位置: 首页 > news >正文

浏览器http提交protobuf二进制数据正常,微信小程序失败解决方案

        最近开发微信小游戏,客户端和服务器端使用http短连接方式post数据,数据的格式使用protobuf,这样通过网络传输的数据是二进制,对于抓包的外挂使用者来说也不容易篡改数据内容。

        之前测试一直使用的是PC浏览器来测试协议,通过浏览器看到不管是格式还是内容都没有问题。

d6c6793df4b54741ab7c7ec0a6fcf214.png

 等到最后收尾的时候,开始导入微信开发者工具里,进行测试,结果出问题了,二进制数据 本应该是上面截图红色圈出来的formdata内容,但是微信开发者工具里查看到的是uint8array结构,

0967899e166244d990790dc81da7e4be.png所以服务器端收到请求后进行反序列化成对象的时候报错,返回失败。

 不过在PC浏览器里却不会发生此问题,所以初步怀疑是PC浏览器在发送protobuf的 uint8array数据的时候会自动转成arrayBuffer 字节,而微信小程序需要手动将uint8array转成arrayBuffer,那么带着这个疑问做了个尝试。

var n = e.prototype;
return n.httpRequest = function (e, t, n, r) {
          t = encodeURI(t);
          var s = new XMLHttpRequest,
          i = function (e, t) {
               s && s.abort && s.abort();
               var r = setInterval((function () {
                    n && n(e, t), clearInterval(r)
               }), 50)
          },
          a = !1,
          u = setTimeout((function () {
              a = !0, i(!1, null), clearInterval(u)
          }), 1e4);  
          this._httpRequestList.push(s), s.open(e, t), s.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"), s.responseType = "blob", s.onreadystatechange = function () {
            4 === s.readyState && (a || (clearInterval(u), 200 === s.status ? i(!0, s.response) : i(!1, null)))
          }.bind(this), s.send(streambuffer)
}

 我们为了验证,将r为protobuf 通过 encode().finish()返回的uint8array转成string,加入如下代码

var  streambuffer = "";

for (var i = 0; i < r.length; i++) {

             streambuffer += String.fromCharCode(r[i]);

}

var n = e.prototype;
return n.httpRequest = function (e, t, n, r) {
          t = encodeURI(t);
          var s = new XMLHttpRequest,
          i = function (e, t) {
               s && s.abort && s.abort();
               var r = setInterval((function () {
                    n && n(e, t), clearInterval(r)
               }), 50)
          },
          a = !1,
          u = setTimeout((function () {
              a = !0, i(!1, null), clearInterval(u)
          }), 1e4);  

          var  streambuffer = "";
          for (var i = 0; i < r.length; i++) {
              streambuffer += String.fromCharCode(r[i]);
          } 

          this._httpRequestList.push(s), s.open(e, t), s.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"), s.responseType = "blob", s.onreadystatechange = function () {
            4 === s.readyState && (a || (clearInterval(u), 200 === s.status ? i(!0, s.response) : i(!1, null)))
          }.bind(this), s.send(streambuffer)
}

验证发现实际上发送的字节长度是202,但是到了网络传输的时候发送了203字节,而且服务器端也收到了203字节

服务器的日志如下:

32428:2022/09/01 16:37:34.457 [I] [GameServiceController.go:20]  login recv msg bytes [10 194 191 1 101 121 74 104 98 71 99 105 79 105 74 73 85 122 73 49 78 105 73 115 73 110 82 53 99 67 73 54 73 107 112 88 86 67 74 57 46 101 121 74 74 90 67 73 54 77 106 69 51 78 106 73 121 79 84 85 48 79 84 81 50 77 84 107 53 78 84 85 121 76 67 74 106 97 71 70 117 98 109 86 115 73 106 111 121 76 67 74 119 98 71 70 48 97 87 81 105 79 106 65 115 73 109 108 104 100 67 73 54 77 84 89 50 77 106 65 121 77 84 81 49 78 67 119 105 90 88 104 119 73 106 111 120 78 106 89 121 77 68 73 52 78 106 85 48 102 81 46 72 101 113 104 90 77 85 49 86 76 90 114 74 81 54 56 57 85 55 83 71 87 73 121 52 72 117 67 53 88 121 50 86 118 106 99 118 97 107 83 114 87 89 18 6 49 48 48 48 49 52]   len:203 

微信开发者工具里查看到的信息如下:

9f0e2558bd144543bfc97784e18d889f.png

 那么是不是本身转的方式有问题,这里有很多开发者都会遇到这样的问题,有人提出在发送的头里加入  headers: { 'Accept':'application/x-protobuf'} } 或者使用headers: { 'content-type':'application/octet-stream'} },但实际没有任何意义,这里我再在这里将content-type和accept的区别顺便说明下:

Content-Type:

Content-Type(内容类型),一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。这个就是经常看到一些网页打开之后会下载一个文件或者是一张图片的原因。

Content-Type代表发送端(客户端/服务器)发送的实体数据的数据类型。

Accept

Accept用来指定什么媒体类型的响应是可接受的,即告诉服务器我需要什么媒体类型的数据,此时服务器应该根据Accept请求头生成指定媒体类型的数据。

Accept表示客户端(浏览器)支持的类型,也是希望服务器响应发送回来的数据类型。

区别

  • Content-Type属于实体头Response Header,Accept属于请求头Request Header

  • Accept代表客户端希望接收到的类型,如Accept: application/json;charset=UTF-8,代表接收JSON数据格式的数据;

    Content-Type代表服务器发送实体数据的类型,如Content-Type: application/xml,代表发送XML数据格式的数据。

  • 两者可以结合使用,如:

    Content-Type: application/json;charset=UTF-8; Accept: text/html;

后边发现应该是在protobuf encode之后得到的uint8array转arraybuff出了问题,需要将uint8array.slice().buffer 发送给后端即可,slice() 方法会 byteLength 自动截取有效的部分,也就是实际需要的数据。

这样就在浏览器里和微信开发者工具里都得到了protobuf的返回 

436e35cef49a400f9c72095600013016.png

 

相关文章:

  • 实现 QQuickImageProvider 的若干问题的思路
  • 算法——查找
  • C/C++语言100题练习计划 82——加勒比海盗船(贪心算法实现)
  • RHCE(四)--- DNS服务的正反向解析配置
  • VUE的侦听器watch
  • ROS1云课→15主题与坐标系
  • 【1. GPIO】
  • Netty——NIO(Selector处理read事件)代码示例
  • 计算机与软件技术系毕业设计(论文)实施意见-计算机毕业设计论文怎么写
  • C/C++语言100题练习计划 83——背包问题(贪心算法实现)
  • JS:数组类型及常用的方法使用
  • Oracle-job跑批变慢案例
  • java/php/python在线求助救援网站vue+elementui
  • Vivado关联Vscode,解决Vscode自动保存和卡顿问题
  • Java基础用Date类编写万年历
  • canvas 绘制双线技巧
  • FineReport中如何实现自动滚屏效果
  • hadoop集群管理系统搭建规划说明
  • Javascript 原型链
  • JavaScript创建对象的四种方式
  • Java读取Properties文件的六种方法
  • Java小白进阶笔记(3)-初级面向对象
  • Mysql数据库的条件查询语句
  • Odoo domain写法及运用
  • Python十分钟制作属于你自己的个性logo
  • Spring Boot快速入门(一):Hello Spring Boot
  • Tornado学习笔记(1)
  • unity如何实现一个固定宽度的orthagraphic相机
  • Vue 重置组件到初始状态
  • vue中实现单选
  • 闭包,sync使用细节
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 如何编写一个可升级的智能合约
  • 深度解析利用ES6进行Promise封装总结
  • 深入浏览器事件循环的本质
  • 我感觉这是史上最牛的防sql注入方法类
  • 移动端解决方案学习记录
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​MySQL主从复制一致性检测
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (五)网络优化与超参数选择--九五小庞
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .Net Remoting(分离服务程序实现) - Part.3
  • .net Signalr 使用笔记
  • .net 程序发生了一个不可捕获的异常
  • .Net的DataSet直接与SQL2005交互
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • .sdf和.msp文件读取
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?