http字节流转字符流的问题

http将des加密的数据请求到服务器,由于des是二进制数据,所以请求时必须以流数据的方式请求web服务器。但是这个时候除了传输流数据,还需要指定des的密钥id,所以导致一个字符串一个流数据,处理起来极为刁钻,如果都放在流数据里面,在web端就需要截取,处理起来也是比较麻烦的,为了解决这个问题,此文应运而生,ps前端是安卓系统,客户端和服务端的java运行环境都是utf-8编码


开始的解决方案是:

1.将原数据(utf-8编码)重新编码成字节流

2.将字节流用des加密得到加密后的字节流

3.再把加密后的字节流转成字符串(utf-8)

4.传输

5.后台接收字符串

6.将字符串编码获取字节流,并且des解密

7.按utf-8解码


启动web,发送请求,一批批乱码蹦出来简直无法直视

经过百般折腾后,终于搞清楚了出现乱码的原因,并且一举揪出各种令人眼花缭乱的编码格式及其使用技巧

分析这次出现乱码的原因本质就是最终得到的字节流已经不是最开始的字节流了,所以要想办法得到最开始的字节流,查阅资料后发现,将字节数据转成utf-8字符串后,再把这个字符串转成字节数据已经不是原来的字节数据了,有点怀疑?直接上代码!

byte resByte [] = {79, 77, 99, 20, -70, 65, -10, -108, -83, 3, 14, 5, -48, -90, 94, -64};
String resStr = new String(resByte,"UTF-8");
byte[] desByte = resStr.getBytes("UTF-8");

运行结果是desByte = {79, 77, 99, 20, -17, -65, -67, 65, -17, -65, -67, -17, -65, -67, -17, -65, -67, 3, 14, 5, -48, -90, 94, -17, -65, -67},显然与resByte不是相等的了

这样的结果无不让人瞠目结舌,同一个字节流,按照utf-8解码后再编码已经不是原来的字节流了,那么这就问题来了,如下转换怎么就没问题?

String resStr = "测试内容";
byte resByte [] = resStr.getBytes("UTF-8");
String desStr = new String(resByte);
System.out.println(desStr);

输出的desStr就是“测试内容”,不是乱码!查阅众多资料无果,希望了解编码原理的同学解答一下,只能暂时先给出结论:不标准的utf-8字节流转成utf-8字符后,再通过utf-8编码回标准的utf-8编码字节流后,已经是标准的utf-8字节流了,不是原来的字节流了

所以后台又按照utf-8编码成字节流是肯定会出错的,怎么办?又查阅资料,发现使用ISO-8859-1编码可以当做字节流来使用,这无疑是春天来了,不过还是先测试一下

byte resByte [] = {79, 77, 99, 20, -70, 65, -10, -108, -83, 3, 14, 5, -48, -90, 94, -64};
String resStr = new String(resByte,"ISO-8859-1");
byte[] desByte = resStr.getBytes("ISO-8859-1");

运行结果desByte= {79, 77, 99, 20, -70, 65, -10, -108, -83, 3, 14, 5, -48, -90, 94, -64}跟原来的字节码一致

结果让人拍案叫绝

赶紧把上面的方案改成如下

1.将原数据(utf-8编码)按照编码成字节流

2.将字节流用des加密得到加密后的字节流

3.把加密后的字节流按照ISO-8859-1转成字符串

4传输

5.后台接收字符串,按照ISO-8859-1获取到字节码

6.将获取到的字节码按照des解密成明文

7.明文按utf-8解码

结果令人大失所望,居然又是乱码,深受致命一击!一步步查看,每一步都能走的通,而且使用明文直接传输中文的时候不会出现乱码,所以否认了环境的问题,肯定这里还有编码的问题,经过在各种百度的摸爬滚打,又找到一个好像有点问题的东西:客户端在传输字符串参数的时候,有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了,所以说,第5步得到的字符串已经不是传输的过来的字符串了,得到的也肯定会是乱码,那么肿么办,java给我们提供了一个很实用的工具URLEncoder.encode只需要将原来需要传输的字符串编码成URL能够传输的字符串就行了,需要注意的是URLEncoder.encode在做转换的时候建议指定编码格式(如果不指定按照java启动时默认的编码格式),如果没有指定将会使用使用默认的(我这里是utf-8),如果是按照默认的格式编码(utf-8),为什么还要指定编码格式,深入到URLEncoder.encode源码,发现,原来这个指定编码不是给encode传入的String用的,而是用于生成如%这些分隔符的编码,所以这些分割码应该保持与encode传入的String是一致的编码格式(ISO-8859-1).很刁钻的是,如果指定utf-8在eclipse使用jetty的时候不会出现乱码,到tomcat里面会出现乱码,tomcat需要指定ISO-8859-1编码,而指定ISO-8859-1的时候,在jetty里面又出乱码了,这个问题出现的原因暂时未知,还需要等后续的深入探究


总结:

1.首先编码本质上可以看成是一张表,两列,一列是字符串,另外一列是对应的字节,每一个字符集都是一张表,如utf-8是一张表、ISO-8859-1是另外一张表

2.String.getBytes("UTF-8"),本质上是将String这个已经解码成字符串(所有的字符串都是已经按照java启动参数指定的字符集解码好了的,也就是说如果我们的java环境编码是utf-8,那么我们所看到String如“你好,世界”其实就是utf-8这张编码表里面的字符串这一列所对应的数据)的数据再次按照utf-8编码回字节,也就是说根据utf-8这张表的字符串这一列查找对应的字节那一列的数据。而new String(byte[],"UTF-8")正好相反,是根据utf-8这张表的字节那一列的数据查找对应字符串那一列的数据。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值