微信小程序的模拟器和真机、支付宝小程序的模拟器接受到数据解析都是正常的,但是支付宝小程序的真机却报错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 一天一夜,上百次的编译调试。非常有成就感!!!
网友评论