JAVA客户端错误_java客户端和GO服务端联调错误

最近遇到一个bug很有意思,java客户端加密后传给服务端,服务端是GO Listen请求后解密处理,但是服务端解密失败。排查过程如下:

1.首先请求过程中有中间服务器转发,因此猜想可能是转发数据错误。由于发送数据为二进制流,因此对比客户端发送时与服务端接收到的数据的md5和base64,一致,排除中间传输错误。

2.再猜想是不是加密解密方法设置不一样导致失败。因为加密解密用的RSA,网上资料显示不同的RSA padding方式以及不同的provider都可能导致加密解密不一致从而解密失败,因此保证都是RSA/ECB/PKCS1Padding填充方式,而且java端两个provider(sun oracle实现和Bouncy Castle实现)都尝试下,还是有问题。

3.这时候没办法了,只能跟踪对比数据流了。在客户端发送二进制时计算数据md5和base64,分别发送二进制和base64数据,然后服务端收到二进制和base64,此时对二进制解密错误,但是对base64数据解码后再解密发现正确。这是为什么呢?对比收到的二进制数据和base64解码后的二进制,发现前者相对后者多了很多239,191,189,这些正是UTF8未识别字符的编码,因此问题就是客户端转二进制流时导致的问题。

下面用代码复现这一过程,

public static void EncodeAndDecode(String charset) throws UnsupportedEncodingException {

System.out.println("

encode and decode with charset:" + charset);

byte[] bytes = new byte[]{80, 75, 3, 4, 10, 60, 82, -83, 68, 8, 0, 28, 0, 80, 97, 121, 108, 108};

System.out.println(Arrays.toString(bytes));

//先转成字符串

String s = new String(bytes, 0, bytes.length, charset);

//System.out.println(s);

//字符串再反转成字节

byte[] bytes2 = s.getBytes(charset);

System.out.println(Arrays.toString(bytes2));

}

UTF8的编码规则如下:

Unicode编码(16进制) UTF-8 字节流(二进制)

000000 – 00007F 0xxxxxxx

000080 – 0007FF 110xxxxx 10xxxxxx

000800 – 00FFFF 1110xxxx 10xxxxxx 10xxxxxx

010000 – 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

转码规则如下:

1.以0,110,1110,11110开头的字节,可以被识别

2.如果以10开头,则要求前一个字节必须以10,110,1110,11110开头

3.如果以10开头且前一个也以10开头,则再前一个必须以10,1110,11110开头

4.如果以10开头且前一个以10开头且再前一个也以10开头,则再前一个必须以11110开头

5.不能被识别的字节,每一个会转换成三个字节{11101111,10111111,10111101},也就是239,191,189

因此,实际编码中先将ASCLL二进制流转成字符串,如果这里是按照GBK编码转换再转回是没任何问题的。但是如果按照UTF-8转换时成字符串时,-83无法识别,会转成字节-17, -65, -67(其实就是239,191,189,因为java中byte-128~127)。

错误演示代码下载链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值