1.问题背景
最近在做内部系统与银行对接的支付网关,其中涉及到跨服务的编码转换问题。
这次遇到的是UTF-8(我们使用的编码)与GBK(某银行使用的编码)的中文传输乱码问题。
刚开始解决乱码问题的时候,心想解决方式无非是:按照编码的格式进行转码。
经过这次问题,对乱码问题有了进一步的认识,原来乱码不仅仅是转入转出格式统一,还涉及到系统编码、IDE工具、tomcat服务等等网络传输带来的问题。
2.解决尝试
主要从系统内UTF-8转GBK输出、接收系统外传输的GBK数据(输入、输出)两方面考试。
(1)系统内UTF-8转GBK
- 使用URLEncoder.encode传输数据,使用时进行decoder
String plainData = java.net.URLEncoder.encode(plainDataR.trim(),"GBK");
java.net.URLDecoder.decode(plainData, "GBK"));
- 页面传输设置编码GBK
<%@ page contentType="text/html; charset=GBK" session="false" %>
(2)接收系统外传输的GBK数据
- 使用string.getBytes()进行转码,需要指定编码格式
string.getBytes()不指定编码将使用系统默认编码或者IDE默认编码进行编译。
String本身没有编码格式,需要指定编码,如果不指定,就会默认使用系统编码。
- 添加filter进行编码设置
获取请求编码,判断若是GBK,将request设置为GBK编码
if("GBK".equals(request.getCharacterEncoding())){
request.setCharacterEncoding(request.getCharacterEncoding());
log.info("====filter======plain="+request.getParameter("Plain"));
}
备注:
注意struts.xml的配置
1).使用StrutsPrepareFilter及StrutsExecuteFilter
添加charsetFilter不生效,最后查明原因是struts2默认编码为UTF-8,经过 StrutsPrepareFilter已将请求过滤成UTF-8编码,再执行charsetFilter已不生效。
在StrutsPrepareFilter和StrutsExecuteFilter之间添加自定义filter.
2) 修改为先执行自定义charsetFilter,再使用FilterDispatcher即可生效。
- 修改tomcat ,取消默认编码设置,增加useBodyEncodingForURI="true"
URIEncoding="UTF-8"
useBodyEncodingForURI="true"
3.问题总结
设置eclipse默认编码为UTF-8,java文件采用UTF-8编码格式进行编译。银行jar包为GBK编码编译,传递GBK编码,调用银行签名算法,报验签失败,最终查看银行jar包代码,问题归根于string.getBytes(),未设置编码格式,采用系统默认编码UTF-8,所以导致验签失败。
最终去掉其他尝试方法,将jar包里签名算法修改为string.getBytes(“GBK”)解决问题。