您當前位置>首頁 » 新聞資(zī)訊 » 小程序相關(guān) >
支付寶小程序MQTT數據Base64錯誤
發表時間:2021-1-5
發布人:葵宇科技
浏覽次數:83
微信小程序的模拟器(qì)和(hé)真機、支付寶小程序的模拟器(qì)接受到數據解析都是正常的,但是支付寶小程序的真機卻報錯 AMQJS0007E Socket error:未能完成操作。(OSStatus錯誤-9807。)
。
結論
支付寶小程序返回的數據為Base64格式,并且 帶有換行符 。所以導緻在解析的時候出現錯誤。 解決方案: 字符串去掉換行符。
data = data.replace(/[\r\n]/g,"");
複制代碼
現象
測試人員反饋說在支付寶小程序上沒有軌迹。一臉懵逼的反應說,不可(kě)能吧。微信都是好的,模拟器(qì)也自測了,沒有問(wèn)題啊。查看現象果然有問(wèn)題啊,啥都不顯示。 因為軌迹使用的是MQTT的推送,不能通(tōng)過charles抓包獲取并查看數據,也沒法通(tōng)過控制台查看日志。也不像微信小程序可(kě)以打開調試模闆。才疏學淺的我,隻能通(tōng)過toast内容來判斷是否出錯。!_! 有好方案請多多指教。
MQTT不支持支付寶小程序的真機?
第一反應就是難道不支持嗎? 打開了mqtt.js看了看。前輩們已經編寫好兼容支付寶小程序,那麼也就是說方案是沒有問(wèn)題的啊。着手添加日志,将出錯的信息打印出來。在使用到mqtt的地方,所有的failure和(hé)catch中(zhōng)都添加日志并打印。
AMQJS0005E Internal error. Error Message: AMQJS0009E malformed UTF data:93 -3d.,Stack trace: No Error Stack Available
Base64格式問(wèn)題?
看到錯誤日志後,問(wèn)了下(xià)度娘“啥原因啊,度娘。”, "要先看廣告哦,不然不告訴你(nǐ)"。看了一些廣告後,說“是不是包含中(zhōng)文(wén)了啊”。 這有可(kě)能哦。找到後台開發人員,提供了登錄的手機号碼,幫忙打印下(xià)發送的原文(wén)是啥。千辛萬苦的找啊找啊,說登錄後馬上就下(xià)線了,沒有發送内容。這。。。 也就是說上上下(xià)下(xià)。還是說沒有添加打印日志的代碼。(誰知道呢(ne))
查找出錯的位置
将mqtt中(zhōng)所有的代碼看一遍,順着報錯的調用棧,在每一個(gè)錯誤分支添加日志。等查看到最小單元的代碼塊後,按行進行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=http://www.wxapp-union.com/{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), ""]));
抛出了異常。可(kě)以很确切的判斷因為Base64轉ArrayBuffer後,進行數據内容的判斷出錯了。
分析ArrayBuffer
要進行判斷數據是否有問(wèn)題,那麼将模拟器(qì)和(hé)真機的數據都打印出來,然後進行比對。
發現固定相同位置的值不一緻,那麼也就是說其中(zhōng)一定是添加或删除了一些字符。
查看Base64字符串
再向上查看小程序直接返回的字符串是否就出現了問(wèn)題,如(rú)果有問(wèn)題,那麼一定是後台針對真機做了特殊的處理!或者真機的arm平台針對某個(gè)方法有不同的處理邏輯!。。。
查看Base64字符串也很正常,将字符串使用Base64标準格式進行解碼後發現有亂碼。好興奮啊,那一定是這個(gè)問(wèn)題了。興沖沖的就找後台開發人員,一定是你(nǐ)們的數據有問(wèn)題。但是...打臉來的很快。從後台的日志中(zhōng)看到返回的數據都是一樣的,根本不區分平台。 再次核對base64的字符串後,發現其中(zhōng)的"l"和(hé)"I"寫錯了。一個(gè)是小寫的L,一個(gè)是大寫的i。可(kě)以确認後台發送過來的base64也是正确的。那麼真相隻有一個(gè):Base64轉ArrayBuffer出錯了。
Base64轉ArrayBuffer
發現微信小程序是有提供方法進行base64轉ArrayBuffer,base64轉string等。但是支付寶小程序卻什麼都沒有,難倒是我沒找到嗎!!!(知道的,請添加下(xià)評論,讓我摩拜下(xià)) 找了很久也沒找到啥靠譜的,最後曲線救國。先将base64轉為string,再将string轉為ArrayBuffer。結果還是失敗了。
猜想
如(rú)果真機和(hé)模拟器(qì)出現問(wèn)題,那麼直接用相同的字符串,也一樣會出現問(wèn)題。 将data直接hard code。然後進行模拟器(qì)和(hé)真機的測試。發現。。。驚喜啊。都成功了,沒有報錯啊。666 可(kě)以得出最後的結論了,真機返回的字符串一定有特殊字符并不可(kě)見。 馬上拿就想到了 空格和(hé)換行符 。
成功
将字符串進行去除換行和(hé)空格後,一切都那麼完美了。 最後多次測試發現是多了換行符。^ _ ^ 将mqtt.js代碼都看了一遍,還是收貨很多啊!