问题起因
昨天做了一个生成微信小程序海报图分享的需求,在后端请求微信小程序API生成二维码时,遇到如下报错;
报错信息:
{"errcode":40169,"errmsg":"invalid length for scene, or the data is not json string rid: 62cd3718-0df31cec-7ae67e56"}
报错原因:
scene的长度不合法,小程序参数scene的长度最大32个可见字符,由于还有一些其他的业务参数要传,所以加起来就超过32位了。
解决方案:
让前端将参数值编码压缩后传入,扫描生成的二维码 解析时,又将参数解码后使用。
编码解码:
/* *
* 压缩
*/
function compress(strNormalString) {
console.log( " 压缩前长度: " + strNormalString.length);
var strCompressedString = "" ;
var ht = new Array();
for (i = 0 ; i < 128 ; i ++ ) {
ht[i] = i;
}
var used = 128 ;
var intLeftOver = 0 ;
var intOutputCode = 0 ;
var pcode = 0 ;
var ccode = 0 ;
var k = 0 ;
for ( var i = 0 ; i < strNormalString.length; i ++ ) {
ccode = strNormalString.charCodeAt(i);
k = (pcode << 8 ) | ccode;
if (ht[k] != null ) {
pcode = ht[k];
} else {
intLeftOver += 12 ;
intOutputCode <<= 12 ;
intOutputCode |= pcode;
pcode = ccode;
if (intLeftOver >= 16 ) {
strCompressedString += String.fromCharCode( intOutputCode >> ( intLeftOver - 16 ) );
intOutputCode &= (Math.pow( 2 , (intLeftOver - 16 )) - 1 );
intLeftOver -= 16 ;
}
if (used < 4096 ) {
used ++ ;
ht[k] = used - 1 ;
}
}
}
if (pcode != 0 ) {
intLeftOver += 12 ;
intOutputCode <<= 12 ;
intOutputCode |= pcode;
}
if (intLeftOver >= 16 ) {
strCompressedString += String.fromCharCode( intOutputCode >> ( intLeftOver - 16 ) );
intOutputCode &= (Math.pow( 2 ,(intLeftOver - 16 )) - 1 );
intLeftOver -= 16 ;
}
if ( intLeftOver > 0 ) {
intOutputCode <<= ( 16 - intLeftOver);
strCompressedString += String.fromCharCode( intOutputCode );
}
console.log(strCompressedString+" 压缩后长度: " + strCompressedString.length);
return strCompressedString;
}
/* *
* 解压缩
*/
function decompress(strCompressedString) {
var strNormalString = "" ;
var ht = new Array();
for (i = 0 ; i < 128 ; i ++ ) {
ht[i] = String.fromCharCode(i);
}
var used = 128 ;
var intLeftOver = 0 ;
var intOutputCode = 0 ;
var ccode = 0 ;
var pcode = 0 ;
var key = 0 ;
for ( var i = 0 ; i < strCompressedString.length; i ++ ) {
intLeftOver += 16 ;
intOutputCode <<= 16 ;
intOutputCode |= strCompressedString.charCodeAt(i);
while ( 1 ) {
if (intLeftOver >= 12 ) {
ccode = intOutputCode >> (intLeftOver - 12 );
if ( typeof ( key = ht[ccode] ) != " undefined " ) {
strNormalString += key;
if (used > 128 ) {
ht[ht.length] = ht[pcode] + key.substr( 0 , 1 );
}
pcode = ccode;
} else {
key = ht[pcode] + ht[pcode].substr( 0 , 1 );
strNormalString += key;
ht[ht.length] = ht[pcode] + key.substr( 0 , 1 );
pcode = ht.length - 1 ;
}
used ++ ;
intLeftOver -= 12 ;
intOutputCode &= (Math.pow( 2 ,intLeftOver) - 1 );
} else {
break ;
}
}
}
console.log(" 解压缩后: " + strNormalString);
return strNormalString;
}
*注:编码和解码的代码在掘金找到的,亲测可用
更新问题
如果参数很长,某些参数通过上述方法编码后,生成的特殊值,微信二维码接口会报参数错误:{"errcode":47001,"errmsg":"data format error rid: 62cff06f-5b9b6b75-4cd4abe1"}
解决办法
后端将参数转成36进制,就可以缩短,前端解析时调用后端的接口,获得36转成10进制的结果即可。
解决代码
String a = new BigInteger("1377441457769660418").toString(36);
System.out.println(a);
BigInteger b = new BigInteger(a, 36);
System.out.println(b);
// 输出:
agqu8tynj8ci
1377441457769660418
UUID压缩及解压
/**
* 压缩
* @param src uuid字符串,可带有{@code -}
* @return base64字符串,length=22
*/
public static String compress(String src) {
UUID uuid = UUID.fromString(src);
long msb = uuid.getMostSignificantBits();
long lsb = uuid.getLeastSignificantBits();
byte[] b = new byte[16];
for (int i = 0; i < 8; i++) {
b[i] = (byte) (msb >>> (8 * (7-i)) & 0xff);
b[i+8] = (byte) (lsb >>> (8 * (7-i)) & 0xff);
}
return Base64.getEncoder().withoutPadding().encodeToString(b);
}
/**
* 解压
* @param src base64字符串,length=22
* @return uuid字符串,{@code -}分割
*/
public static String decompress(String src) {
byte[] b = Base64.getDecoder().decode(src);
long msb = 0;
long lsb = 0;
for (int i=0; i<8; i++) {
msb = (msb << 8) | (b[i] & 0xff);
lsb = (lsb << 8) | (b[i+8] & 0xff);
}
return new UUID(msb, lsb).toString();
}