记录一次生成微信小程序二维码报错的解决方案

1,479 阅读3分钟

问题起因

昨天做了一个生成微信小程序海报图分享的需求,在后端请求微信小程序API生成二维码时,遇到如下报错;

报错信息:

{"errcode":40169,"errmsg":"invalid length for scene, or the data is not json string rid: 62cd3718-0df31cec-7ae67e56"}

image.png

报错原因:

scene的长度不合法,小程序参数scene的长度最大32个可见字符,由于还有一些其他的业务参数要传,所以加起来就超过32位了。

image.png

解决方案:

让前端将参数值编码压缩后传入,扫描生成的二维码 解析时,又将参数解码后使用。

编码解码:

 /* *
  * 压缩
  */ 
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();
}