美文网首页
支付宝小程序MQTT数据Base64错误

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

作者: 蝴蝶之梦天使 | 来源:发表于2020-09-09 14:35 被阅读0次
    MQTT

    微信小程序的模拟器和真机、支付宝小程序的模拟器接受到数据解析都是正常的,但是支付宝小程序的真机却报错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标准格式进行解码后发现有乱码。好兴奋啊,那一定是这个问题了。兴冲冲的就找后台开发人员,一定是你们的数据有问题。但是...打脸来的很快。从后台的日志中看到返回的数据都是一样的,根本不区分平台。
    再次核对base64的字符串后,发现其中的"l"和"I"写错了。一个是小写的L,一个是大写的i。可以确认后台发送过来的base64也是正确的。那么真相只有一个:Base64转ArrayBuffer出错了。

    Base64转ArrayBuffer

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

    猜想

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

    成功

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

    // END 一天一夜,上百次的编译调试。非常有成就感!!!

    相关文章

      网友评论

          本文标题:支付宝小程序MQTT数据Base64错误

          本文链接:https://www.haomeiwen.com/subject/rxeeektx.html