Java 和 JavaScript 真正通用的Base64编码详解
Java和JavaScriptBase64编码
在开发Java Web应用的时候,可能会在服务器端用Java做Base64编码,而在客户端用JavaScript进行解码。这样就要求两边的Base64编码机制保持一致。
使用Base64编码,可能会碰到各种奇怪情况,甚至怀疑编码有bug。但实际上不是这样的。Base64理论上操作的对象不是字符串而是字节数组。它的原理就是把ASCII码的255个字符缩小到用64个来表示。具体就是原来三个字节用四个字节表示,编码后长度有一定的增长。
1)最好一次编码,避免分段编码,确实要分段编码,每一段字节数应该是3的倍数。
长字节流,如果要边读取边编码,每一段必须是3的倍数,否则就可能在还原的时候出乱。一般人喜欢用2的乘方来定义数组,例如byte[1024],因为不是3的倍数,可能还原时出错。正确的例子是:
byte[]bs=newbyte[3*100]....inputStream.read(bs)......encode(bs)....
对于字符串,一般要整个一次编码,以避免分段编码出错。
当然,如果你分段编码,还原的时候也是一段一段地还原,那是没有问题的。
2)确保字符串还原的时候按照原来的编码还原。
因为它操作的是字节数组,所以对于GBK编码的汉字和UTF-8编码汉字,经过Base64编码后结果是不一样的。例如“我们”这两个字如果是GBK编码,转成Base64后就是ztLDxw==;如果是UTF-8编码,转成Base64后就是5oiR5Lus。
也就是“我们”==》 getBytes("GBK")==>Base64
所以Java这边用什么编码转换,在JavaScript那边就要用什么编码还原。要保证Java和JavaScript通用,我们采用Unicode的编码(JavaScript转成UTF-8、GBK不方便,所以就采用了其本身的Unicode编码),具体如下:
服务器端:
1)用getBytes("Unicode")转成Unicode字节数组。
2)编码成Base64字符串
3)传送到客户端
客户端:
1)Base64解码成字节数组
2)按Unicode还原
代码如下(相关的函数看附件):
Base64.encode(data,"Unicode");//java端编码
decode64(data); //javascript解码
附一:Java中Base64编码
packagewebsharp.util;
publicclassBase64{
privatestaticfinalbyte[]encodingTable={
(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',
(byte)'F',(byte)'G',(byte)'H',(byte)'I',(byte)'J',
(byte)'K',(byte)'L',(byte)'M',(byte)'N',(byte)'O',
(byte)'P',(byte)'Q',(byte)'R',(byte)'S',(byte)'T',
(byte)'U',(byte)'V',(byte)'W',(byte)'X',(byte)'Y',
(byte)'Z',(byte)'a',(byte)'b',(byte)'c',(byte)'d',
(byte)'e',(byte)'f',(byte)'g',(byte)'h',(byte)'i',
(byte)'j',(byte)'k',(byte)'l',(byte)'m',(byte)'n',
(byte)'o',(byte)'p',(byte)'q',(byte)'r',(byte)'s',
(byte)'t',(byte)'u',(byte)'v',(byte)'w',(byte)'x',
(byte)'y',(byte)'z',(byte)'0',(byte)'1',(byte)'2',
(byte)'3',(byte)'4',(byte)'5',(byte)'6',(byte)'7',
(byte)'8',(byte)'9',(byte)'+',(byte)'/'
};
privatestaticfinalbyte[]decodingTable;
static{
decodingTable=newbyte[128];
for(inti=0;i<128;i++){
decodingTable[i]=(byte)-1;
}
for(inti='A';i<='Z';i++){
decodingTable[i]=(byte)(i-'A');
}
for(inti='a';i<='z';i++){
decodingTable[i]=(byte)(i-'a'+26);
}
for(inti='0';i<='9';i++){
decodingTable[i]=(byte)(i-'0'+52);
}
decodingTable['+']=62;
decodingTable['/']=63;
}
publicstaticbyte[]encode(byte[]data,intoffset){
byte[]bytes;
intrealCount=data.length-offset;
intmodulus=realCount%3;
if(modulus==0){
bytes=newbyte[(4*realCount)/3];
}else{
bytes=newbyte[4*((realCount/3)+1)];
}
intdataLength=(data.length-modulus);
inta1;
inta2;
inta3;
for(inti=offset,j=0;i<dataLength;i+=3,j+=4){
a1=data[i]&0xff;
a2=data[i+1]&0xff;
a3=data[i+2]&0xff;
bytes[j]=encodingTable[(a1>>>2)&0x3f];
bytes[j+1]=encodingTable[((a1<<4)|(a2>>>4))&0x3f];
bytes[j+2]=encodingTable[((a2<<2)|(a3>>>6))&0x3f];
bytes[j+3]=encodingTable[a3&0x3f];
}
intb1;
intb2;
intb3;
intd1;
intd2;
switch(modulus){
case0:/*nothinglefttodo*/
break;
case1:
d1=data[data.length-1]&0xff;
b1=(d1>>>2)&0x3f;
b2=(d1<<4)&0x3f;
bytes[bytes.length-4]=encodingTable[b1];
bytes[bytes.length-3]=encodingTable[b2];
bytes[bytes.length-2]=(byte)'=';
bytes[bytes.length-1]=(byte)'=';
break;
case2:
d1=data[data.length-2]&0xff;
d2=data[data.length-1]&0xff;
b1=(d1>>>2)&0x3f;
b2=((d1<<4)|(d2>>>4))&0x3f;
b3=(d2<<2)&0x3f;
bytes[bytes.length-4]=encodingTable[b1];
bytes[bytes.length-3]=encodingTable[b2];
bytes[bytes.length-2]=encodingTable[b3];
bytes[bytes.length-1]=(byte)'=';
break;
}
returnbytes;
}
publicstaticbyte[]decode(byte[]data){
byte[]bytes;
byteb1;
byteb2;
byteb3;
byteb4;
data=discardNonBase64Bytes(data);
if(data[data.length-2]=='='){
bytes=newbyte[(((data.length/4)-1)*3)+1];
}elseif(data[data.length-1]=='='){
bytes=newbyte[(((data.length/4)-1)*3)+2];
}else{
bytes=newbyte[((data.length/4)*3)];
}
for(inti=0,j=0;i<(data.length-4);i+=4,j+=3){
b1=decodingTable[data[i]];
b2=decodingTable[data[i+1]];
b3=decodingTable[data[i+2]];
b4=decodingTable[data[i+3]];
bytes[j]=(byte)((b1<<2)|(b2>>4));
bytes[j+1]=(byte)((b2<<4)|(b3>>2));
bytes[j+2]=(byte)((b3<<6)|b4);
}
if(data[data.length-2]=='='){
b1=decodingTable[data[data.length-4]];
b2=decodingTable[data[data.length-3]];
bytes[bytes.length-1]=(byte)((b1<<2)|(b2>>4));
}elseif(data[data.length-1]=='='){
b1=decodingTable[data[data.length-4]];
b2=decodingTable[data[data.length-3]];
b3=decodingTable[data[data.length-2]];
bytes[bytes.length-2]=(byte)((b1<<2)|(b2>>4));
bytes[bytes.length-1]=(byte)((b2<<4)|(b3>>2));
}else{
b1=decodingTable[data[data.length-4]];
b2=decodingTable[data[data.length-3]];
b3=decodingTable[data[data.length-2]];
b4=decodingTable[data[data.length-1]];
bytes[bytes.length-3]=(byte)((b1<<2)|(b2>>4));
bytes[bytes.length-2]=(byte)((b2<<4)|(b3>>2));
bytes[bytes.length-1]=(byte)((b3<<6)|b4);
}
returnbytes;
}
publicstaticbyte[]decode(Stringdata){
byte[]bytes;
byteb1;
byteb2;
byteb3;
byteb4;
data=discardNonBase64Chars(data);
if(data.charAt(data.length()-2)=='='){
bytes=newbyte[(((data.length()/4)-1)*3)+1];
}elseif(data.charAt(data.length()-1)=='='){
bytes=newbyte[(((data.length()/4)-1)*3)+2];
}else{
bytes=newbyte[((data.length()/4)*3)];
}
for(inti=0,j=0;i<(data.length()-4);i+=4,j+=3){
b1=decodingTable[data.charAt(i)];
b2=decodingTable[data.charAt(i+1)];
b3=decodingTable[data.charAt(i+2)];
b4=decodingTable[data.charAt(i+3)];
bytes[j]=(byte)((b1<<2)|(b2>>4));
bytes[j+1]=(byte)((b2<<4)|(b3>>2));
bytes[j+2]=(byte)((b3<<6)|b4);
}
if(data.charAt(data.length()-2)=='='){
b1=decodingTable[data.charAt(data.length()-4)];
b2=decodingTable[data.charAt(data.length()-3)];
bytes[bytes.length-1]=(byte)((b1<<2)|(b2>>4));
}elseif(data.charAt(data.length()-1)=='='){
b1=decodingTable[data.charAt(data.length()-4)];
b2=decodingTable[data.charAt(data.length()-3)];
b3=decodingTable[data.charAt(data.length()-2)];
bytes[bytes.length-2]=(byte)((b1<<2)|(b2>>4));
bytes[bytes.length-1]=(byte)((b2<<4)|(b3>>2));
}else{
b1=decodingTable[data.charAt(data.length()-4)];
b2=decodingTable[data.charAt(data.length()-3)];
b3=decodingTable[data.charAt(data.length()-2)];
b4=decodingTable[data.charAt(data.length()-1)];
bytes[bytes.length-3]=(byte)((b1<<2)|(b2>>4));
bytes[bytes.length-2]=(byte)((b2<<4)|(b3>>2));
bytes[bytes.length-1]=(byte)((b3<<6)|b4);
}
for(inti=0;i<bytes.length;i++)System.out.println(","+bytes[i]);
returnbytes;
}
privatestaticbyte[]discardNonBase64Bytes(byte[]data){
byte[]temp=newbyte[data.length];
intbytesCopied=0;
for(inti=0;i<data.length;i++){
if(isValidBase64Byte(data[i])){
temp[bytesCopied++]=data[i];
}
}
byte[]newData=newbyte[bytesCopied];
System.arraycopy(temp,0,newData,0,bytesCopied);
returnnewData;
}
privatestaticStringdiscardNonBase64Chars(Stringdata){
StringBuffersb=newStringBuffer();
intlength=data.length();
for(inti=0;i<length;i++){
if(isValidBase64Byte((byte)(data.charAt(i)))){
sb.append(data.charAt(i));
}
}
returnsb.toString();
}
privatestaticbooleanisValidBase64Byte(byteb){
if(b=='='){
returntrue;
}elseif((b<0)||(b>=128)){
returnfalse;
}elseif(decodingTable[b]==-1){
returnfalse;
}
returntrue;
}
publicstaticStringencode(Stringdata,Stringcharset)throwsException
{
//byte[]result=(data.getBytes("Unicode"));
if(data==null||data.length()==0)returndata;
intoffset=0;
//getBytes("unicode")转完后会在前头加上两字节”FE“
byte[]result=encode(data.getBytes(charset),offset);
StringBuffersb=newStringBuffer(result.length);
for(inti=0;i<result.length;i++)sb.append((char)result[i]);
returnsb.toString();
}
publicstaticStringdecode(Stringdata,Stringcharset)throwsException
{
if(data==null||data.length()==0)returndata;
returnnewString(Base64.decode(data),charset);
}
publicstaticvoidmain(String[]args)throwsException{
Stringdata="我们";
Stringdata1=encode(data,"Unicode");
Stringdata2=decode(data1,"Unicode");
System.out.println(data);
System.out.println(data1);
System.out.println(data2);
}
}
附二:JavaScript中Base64编码
<html>
<head>
<title>base64Encoding/Decoding</title>
</head>
<scripttype="text/javascript"><!--
varkeyStr="ABCDEFGHIJKLMNOP"+
"QRSTUVWXYZabcdef"+
"ghijklmnopqrstuv"+
"wxyz0123456789+/"+
"=";
functionencode64(input){
input=unicodetoBytes(input);
varoutput="";
varchr1,chr2,chr3="";
varenc1,enc2,enc3,enc4="";
vari=0;
do{
chr1=input[i++];
chr2=input[i++];
chr3=input[i++];
enc1=chr1>>2;
enc2=((chr1&3)<<4)|(chr2>>4);
enc3=((chr2&15)<<2)|(chr3>>6);
enc4=chr3&63;
if(isNaN(chr2)){
enc3=enc4=64;
}elseif(isNaN(chr3)){
enc4=64;
}
output=output+
keyStr.charAt(enc1)+
keyStr.charAt(enc2)+
keyStr.charAt(enc3)+
keyStr.charAt(enc4);
chr1=chr2=chr3="";
enc1=enc2=enc3=enc4="";
}while(i<input.length);
returnoutput;
}
functiondecode64(input){
varoutput="";
varchr1,chr2,chr3="";
varenc1,enc2,enc3,enc4="";
vari=0;
//removeallcharactersthatarenotA-Z,a-z,0-9,+,/,or=
varbase64test=/[^A-Za-z0-9/+///=]/g;
if(base64test.exec(input)){
alert("Therewereinvalidbase64charactersintheinputtext./n"+
"Validbase64charactersareA-Z,a-z,0-9,'+','/',and'='/n"+
"Expecterrorsindecoding.");
}
input=input.replace(/[^A-Za-z0-9/+///=]/g,"");
output=newArray();
do{
enc1=keyStr.indexOf(input.charAt(i++));
enc2=keyStr.indexOf(input.charAt(i++));
enc3=keyStr.indexOf(input.charAt(i++));
enc4=keyStr.indexOf(input.charAt(i++));
chr1=(enc1<<2)|(enc2>>4);
chr2=((enc2&15)<<4)|(enc3>>2);
chr3=((enc3&3)<<6)|enc4;
output.push(chr1);
if(enc3!=64){
output.push(chr2);
}
if(enc4!=64){
output.push(chr3);
}
chr1=chr2=chr3="";
enc1=enc2=enc3=enc4="";
}while(i<input.length);
returnbytesToUnicode(output);
}
functionunicodetoBytes(s)
{
varresult=newArray();
if(s==null||s=="")returnresult;
result.push(255);//add"FE"tohead
result.push(254);
for(vari=0;i<s.length;i++)
{
varc=s.charCodeAt(i).toString(16);
if(c.length==1)i="000"+c;
elseif(c.length==2)c="00"+c;
elseif(c.length==3)c="0"+c;
varvar1=parseInt(c.substring(2),16);
varvar2=parseInt(c.substring(0,2),16);
result.push(var1);
result.push(var2);
}
returnresult;
}
functionbytesToUnicode(bs)
{
varresult="";
varoffset=0;
if(bs.length>=2&&bs[0]==255&&bs[1]==254)offset=2;//delete"FE"
for(vari=offset;i<bs.length;i+=2)
{
varcode=bs[i]+(bs[i+1]<<8);
result+=String.fromCharCode(code);
}
returnresult;
}
//-->
</script>
<body>
<formname="base64Form">
Typeinthemessageyouwanttoencodeinbase64,orpaste<br>
base64encodedtextintothetextfield,selectEncodeorDecode,<br>
andclickthebutton!<br>
<textareaname="theText"cols="40"rows="6"></textarea><br>
<inputtype="button"name="encode"value="Encodetobase64"
onClick="document.base64Form.theText.value=encode64(document.base64Form.theText.value);">
<inputtype="button"name="decode"value="Decodefrombase64"
onClick="document.base64Form.theText.value=decode64(document.base64Form.theText.value);">
</form>
</body>
</html>
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!