用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 实战教程 查看内容

支付宝小程序MQTT数据Base64错误

Rolan 2020-9-10 10:33

支付宝小程序返回的数据为Base64格式,并且 带有换行符 。所以导致在解析的时候出现错误。 解决方案: 字符串去掉换行符。

微信小程序的模拟器和真机、支付宝小程序的模拟器接受到数据解析都是正常的,但是支付宝小程序的真机却报错 AMQJS0007E Socket error:未能完成操作。(OSStatus错误-9807。)

结论

支付宝小程序返回的数据为Base64格式,并且 带有换行符 。所以导致在解析的时候出现错误。 解决方案: 字符串去掉换行符。

data = data.replace(/[\r\n]/g,"");
复制代码

现象

测试人员反馈说在支付宝小程序上没有轨迹。一脸懵逼的反应说,不可能吧。微信都是好的,模拟器也自测了,没有问题啊。查看现象果然有问题啊,啥都不显示。 因为轨迹使用的是MQTT的推送,不能通过charles抓包获取并查看数据,也没法通过控制台查看日志。也不像微信小程序可以打开调试模板。才疏学浅的我,只能通过toast内容来判断是否出错。!_! 有好方案请多多指教。

MQTT不支持支付宝小程序的真机?

第一反应就是难道不支持吗? 打开了mqtt.js看了看。前辈们已经编写好兼容支付宝小程序,那么也就是说方案是没有问题的啊。着手添加日志,将出错的信息打印出来。在使用到mqtt的地方,所有的failure和catch中都添加日志并打印。

AMQJS0005E Internal error. Error Message: AMQJS0009E malformed UTF data:93 -3d.,Stack trace: No Error Stack Available

Base64格式问题?

看到错误日志后,问了下度娘“啥原因啊,度娘。”, "要先看广告哦,不然不告诉你"。看了一些广告后,说“是不是包含中文了啊”。 这有可能哦。找到后台开发人员,提供了登录的手机号码,帮忙打印下发送的原文是啥。千辛万苦的找啊找啊,说登录后马上就下线了,没有发送内容。这。。。 也就是说上上下下。还是说没有添加打印日志的代码。(谁知道呢)

查找出错的位置

将mqtt中所有的代码看一遍,顺着报错的调用棧,在每一个错误分支添加日志。等查看到最小单元的代码块后,按行进行try-catch,找到指定的行。

var ERROR = {
      OK: { code: 0, text: "AMQJSC0000I OK." },
      CONNECT_TIMEOUT: { code: 1, text: "AMQJSC0001E Connect timed out." },
      SUBSCRIBE_TIMEOUT: { code: 2, text: "AMQJS0002E Subscribe timed out." },
      UNSUBSCRIBE_TIMEOUT: { code: 3, text: "AMQJS0003E Unsubscribe timed out." },
      PING_TIMEOUT: { code: 4, text: "AMQJS0004E Ping timed out." },
      INTERNAL_ERROR: { code: 5, text: "AMQJS0005E Internal error. Error Message: {0}, Stack trace: {1}" },
      CONNACK_RETURNCODE: { code: 6, text: "AMQJS0006E Bad Connack return code:{0} {1}." },
      SOCKET_ERROR: { code: 7, text: "AMQJS0007E Socket error:{0}." },
      SOCKET_CLOSE: { code: 8, text: "AMQJS0008I Socket closed." },
      MALFORMED_UTF: { code: 9, text: "AMQJS0009E Malformed UTF data:{0} {1} {2}." },
      UNSUPPORTED: { code: 10, text: "AMQJS0010E {0} is not supported by this browser." },
      INVALID_STATE: { code: 11, text: "AMQJS0011E Invalid state {0}." },
      INVALID_TYPE: { code: 12, text: "AMQJS0012E Invalid type {0} for {1}." },
      INVALID_ARGUMENT: { code: 13, text: "AMQJS0013E Invalid argument {0} for {1}." },
      UNSUPPORTED_OPERATION: { code: 14, text: "AMQJS0014E Unsupported operation." },
      INVALID_STORED_DATA: { code: 15, text: "AMQJS0015E Invalid data in local storage key={0} value={1}." },
      INVALID_MQTT_MESSAGE_TYPE: { code: 16, text: "AMQJS0016E Invalid MQTT message type {0}." },
      MALFORMED_UNICODE: { code: 17, text: "AMQJS0017E Malformed Unicode string:{0} {1}." },
      BUFFER_FULL: { code: 18, text: "AMQJS0018E Message buffer is full, maximum buffer size: {0}." },
    };
复制代码

首先看到的报错的内容来源,原来错误的日志是mqtt报的。报错的代码为

function parseUTF8(input, offset, length) {
      var output = "";
      var utf16;
      var pos = offset;

      while (pos < offset + length) {
        var byte1 = input[pos++];
        if (byte1 < 128)
          utf16 = byte1;
        else {
          var byte2 = input[pos++] - 128;
          if (byte2 < 0)
            throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), ""]));
          if (byte1 < 0xE0) // 2 byte character
            utf16 = 64 * (byte1 - 0xC0) + byte2;
          else {
            var byte3 = input[pos++] - 128;
            if (byte3 < 0)
              throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16)]));
            if (byte1 < 0xF0) // 3 byte character
              utf16 = 4096 * (byte1 - 0xE0) + 64 * byte2 + byte3;
            else {
              var byte4 = input[pos++] - 128;
              if (byte4 < 0)
                throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16), byte4.toString(16)]));
              if (byte1 < 0xF8) // 4 byte character
                utf16 = 262144 * (byte1 - 0xF0) + 4096 * byte2 + 64 * byte3 + byte4;
              else // longer encodings are not supported
                throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16), byte4.toString(16)]));
            }
          }
        }

        if (utf16 > 0xFFFF) // 4 byte character - express as a surrogate pair
        {
          utf16 -= 0x10000;
          output += String.fromCharCode(0xD800 + (utf16 >> 10)); // lead character
          utf16 = 0xDC00 + (utf16 & 0x3FF); // trail character
        }
        output += String.fromCharCode(utf16);
      }
      return output;
    }
复制代码

在位置 throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), ""])); 抛出了异常。可以很确切的判断因为Base64转ArrayBuffer后,进行数据内容的判断出错了。

分析ArrayBuffer

要进行判断数据是否有问题,那么将模拟器和真机的数据都打印出来,然后进行比对。

发现固定相同位置的值不一致,那么也就是说其中一定是添加或删除了一些字符。

查看Base64字符串

再向上查看小程序直接返回的字符串是否就出现了问题,如果有问题,那么一定是后台针对真机做了特殊的处理!或者真机的arm平台针对某个方法有不同的处理逻辑!。。。

查看Base64字符串也很正常,将字符串使用Base64标准格式进行解码后发现有乱码。好兴奋啊,那一定是这个问题了。兴冲冲的就找后台开发人员,一定是你们的数据有问题。但是...打脸来的很快。从后台的日志中看到返回的数据都是一样的,根本不区分平台。 再次核对base64的字符串后,发现其中的"l"和"I"写错了。一个是小写的L,一个是大写的i。可以确认后台发送过来的base64也是正确的。那么真相只有一个:Base64转ArrayBuffer出错了。

Base64转ArrayBuffer

发现微信小程序是有提供方法进行base64转ArrayBuffer,base64转string等。但是支付宝小程序却什么都没有,难倒是我没找到吗!!!(知道的,请添加下评论,让我摩拜下) 找了很久也没找到啥靠谱的,最后曲线救国。先将base64转为string,再将string转为ArrayBuffer。结果还是失败了。

猜想

如果真机和模拟器出现问题,那么直接用相同的字符串,也一样会出现问题。 将data直接hard code。然后进行模拟器和真机的测试。发现。。。惊喜啊。都成功了,没有报错啊。666 可以得出最后的结论了,真机返回的字符串一定有特殊字符并不可见。 马上拿就想到了 空格和换行符

成功

将字符串进行去除换行和空格后,一切都那么完美了。 最后多次测试发现是多了换行符。^ _ ^ 将mqtt.js代码都看了一遍,还是收货很多啊!

鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏