最近碰到一个需求,后端返回base64格式的数据,前端需要进行base64格式解码,好了,前端采用内部提供的atob函数进行解码,开完成,交付测试,然后测试返回说中文乱码!
然后查了一下,我后端代码采用utf8编码,这没问题,问题出在前端使用的atob函数,它居然采用的是Latin1(ISO-8859-1)编码!还不能修改编码方式,而且它还只在web端开发有这个atob函数!也不知道写这个atob函数的作者出于什么目的,Latin1(ISO-8859-1)编码用的很广么?竖中指!!!!
没办法,问题要解决,我们本可以找一下第三方的包,但想想,还是觉的自己实现一个转码的函数,留着备用,这里分享出来:
let base64util = function () { let _keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; //base64格式加密 function encode(input) { if (typeof input != "string") { input = JSON.stringify(input) } //utf8转码 let buffer = []; for (var n = 0; n < input.length; n++) { var c = input.charCodeAt(n); if (c < 128) { //一个字节 buffer.push(c); } else if (c < 2048) { //两个字节 buffer.push((c >> 6) | 192, (c & 63) | 128); } else if (c < 65536) { //三个字节 buffer.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128); } else if (c < 2097152) { //四个字节 buffer.push((c >> 18) | 240, ((c >> 12) & 63) | 128, ((c >> 6) & 63) | 128, (c & 63) | 128); } else if (c < 67108863) { //五个字节 buffer.push((c >> 24) | 248, ((c >> 18) & 63) | 128, ((c >> 12) & 63) | 128, ((c >> 6) & 63) | 128, (c & 63) | 128); } else { //六个字节 buffer.push((c >> 30) | 252, ((c >> 24) & 63) | 128, ((c >> 18) & 63) | 128, ((c >> 12) & 63) | 128, ((c >> 6) & 63) | 128, (c & 63) | 128); } } //转码 let i = 0, padding = buffer.length % 3; padding && buffer.push(...new Array(padding = 3 - padding).fill(0));//先用0填补 let result = [] while (i < buffer.length) { let [c1, c2, c3] = [buffer[i++], buffer[i++], buffer[i++]]; result.push(c1 >> 2, ((c1 & 0b11) << 4) | (c2 >> 4), ((c2 & 0b1111) << 2) | (c3 >> 6), c3 & 63); } padding && (result.splice(result.length - padding), result.push(...new Array(padding).fill(64)));//把0填补换成= return result.map(v => _keys.charAt(v)).join(""); } //base64格式解码 function decode(input) { if (typeof input != "string") { throw "invalid argument" } //解码 let buffer = input.split(""), i = 0, padding; let r = [] while (i < buffer.length) { let array = buffer.slice(i, i += 4).map(v => _keys.indexOf(v)) if (array.length != 4 || array.some(v => v < 0)) throw "invalid input" padding = array.filter(v => v == 64).length;//获取填补的=号数量 padding && (array.splice(r.length - padding), array.push(...new Array(padding).fill(0)));//把=填补换成0 let [e1, e2, e3, e4] = array r.push((e1 << 2) | (e2 >> 4), ((e2 & 15) << 4) | (e3 >> 2), ((e3 & 3) << 6) | e4); } padding && r.splice(r.length - padding)//去掉填补 //utf8转码 i = 0; buffer = []; while (i < r.length) { let c = r[i++] if (c < 128) //一个字节 buffer.push(c); else if (c < 224) //两个字节 buffer.push(((c & 0b11111) << 6) | (r[i++] & 63)); else if (c < 240) //三个字节 buffer.push(((c & 0b1111) << 12) | ((r[i++] & 63) << 6) | (r[i++] & 63)); else if (c < 248) //四个字节 buffer.push(((c & 0b1111) << 18) | ((r[i++] & 63) << 12) | ((r[i++] & 63) << 6) | (r[i++] & 63)); else if (c < 252) //五个字节 buffer.push(((c & 0b1111) << 24) | ((r[i++] & 63) << 18) | ((r[i++] & 63) << 12) | ((r[i++] & 63) << 6) | (r[i++] & 63)); else //六个字节 buffer.push(((c & 0b1111) << 30) | ((r[i++] & 63) << 25) | ((r[i++] & 63) << 18) | ((r[i++] & 63) << 12) | ((r[i++] & 63) << 6) | (r[i++] & 63)); } return buffer.map(v => String.fromCharCode(v)).join(""); } return { encode, decode }; atob }()
使用:
//转码 base64util.encode("say:上山打老虎") //解码 base64util.decode("c2F5OuS4iuWxseaJk+iAgeiZjg==")
结果: