如何在生成QR码前对JWT进行高效压缩?优先适配浏览器端JS环境
解决方案
1 优先优化JWT结构(降本效果最明显,可直接减少70%以上体积)
- 替换为短声明名:JWT载荷不要用自定义长字段名,全部替换为1-2字符的短别名,比如
userId改u、deviceId改d,标准声明直接用JWT规定的原生短名:iss(签发者)、exp(有效期)、iat(签发时间)即可,无需自定义长名。 - 简化嵌套签名逻辑:无需在外层JWT中嵌套完整内层JWT。后端签发内层JWT时同步生成一个8~12位的唯一标识
inner_id,和内层JWT的映射关系存在后端缓存(有效期和内层JWT一致为12周),外层JWT仅需携带inner_id、1分钟有效期exp、客户端签名三个字段即可,外层JWT长度可直接降到100字节以内,二维码尺寸会大幅缩小。扫码端拿到inner_id后请求后端换取完整内层JWT做验签即可。
2 高效压缩方案(适合无法修改JWT结构的场景)
普通压缩工具效果差是因为JWT本身已经是Base64URL编码格式,通用压缩算法对这类编码后内容的压缩率极低。推荐使用面向二进制优化的DEFLATE算法,浏览器端可直接依赖pako库实现,压缩后转Base64URL编码,比普通gzip压缩效率高15%~30%。
示例代码:
import pako from 'pako'; // JWT压缩函数(生成二维码端用) function compressJwt(jwtStr) { // 转Uint8Array后压缩 const uint8 = new TextEncoder().encode(jwtStr); const compressed = pako.deflateRaw(uint8); // 转Base64URL适配二维码编码规则 return btoa(String.fromCharCode(...compressed)) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, ''); } // JWT解压函数(扫码端用) function decompressJwt(compressedStr) { // Base64URL转码还原 const str = atob(compressedStr.replace(/-/g, '+').replace(/_/g, '/')); const uint8 = new Uint8Array(str.split('').map(c => c.charCodeAt(0))); const decompressed = pako.inflateRaw(uint8); return new TextDecoder().decode(decompressed); }
3 二维码生成优化
浏览器端推荐用qrcode库,调整参数降低二维码冗余:
import QRCode from 'qrcode'; async function generateSmallQr(content) { return QRCode.toDataURL(content, { errorCorrectionLevel: 'L', // 低容错等级,仅7%纠错,适合近距离扫码场景,比默认M级减少20%模块数 margin: 1, // 边距从默认4改成1,进一步缩小整体尺寸 width: 128 // 按需设置输出像素尺寸,不会影响扫码识别率 }); }
内容的提问来源于stack exchange,提问作者Evert
相关产品推荐
相关产品推荐

