每次遇到编码问题大概都要去找一找代码中中文的处理是否妥当,这次找了半天没找到,甚至更换了功能实现方式,发现问题不在编码而是在服务器设置。回头想来,走在自以为正确的道路上真的是一件很恐怖的事情,你会沿着条路走很远,到最后发现依然没有解决问题,好在这是在学习实践的路上,任何尝试都可以放在以后作为积累重新再回馈回来。放在当下,这就是一条道走到黑,不撞南墙不回头。
问题原因
还是很久之前的微信公众号网页项目,在复制详情做为新表单跳转到显示页面时候出现中文乱码问题。
解决办法
http访问转为https,Tomcat配置443端口时,编码也需要同步设置上 URIEncoding="UTF-8"
<Connector port="80" protocol="HTTP/1.1" URIEncoding="UTF-8"
connectionTimeout="20000" redirectPort="443" />
<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol" URIEncoding="UTF-8"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" keystoreFile="/tomcat/conf/cert/xxx.pfx" keystoreType="PKCS12" keystorePass="xxx"/>
问题解决了,但这次解决问题的过程以及考虑过程可以拿出来警醒下自己。
这次编码问题第一个想到的就是说中文乱码嘛,找到乱码的那个参数给统一utf-8就行了如下:
new String(pmap.get("namexx").getBytes("ISO-8859-1"),"utf-8")
尝试过后,结果就是换了一种乱码。。。
鉴于上一次中文乱码问题加了个过滤器解决了,这次也上一个过滤器试试呢,如下:
/**
* ClassName: CharacterEncodingFilter
* @Description: 处理请求参数乱码问题
*/
public class CharacterEncodingFilter implements Filter {
protected String encoding = null;
protected FilterConfig filterConfig = null;
protected boolean ignore = true;
@Override
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)throws IOException, ServletException {
if (ignore || (request.getCharacterEncoding() == null)) {
String encoding= selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
// 获取初始化参数
this.encoding = filterConfig.getInitParameter("encoding");
String value= filterConfig.getInitParameter("ignore");
if (value == null) {
this.ignore = true;
}else if (value.equalsIgnoreCase("true")) {
this.ignore = true;
}else if (value.equalsIgnoreCase("yes")) {
this.ignore = true;
}else
this.ignore = false;
}
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
web.xml
<filter>
<filter-name>Character Encoding</filter-name>
<filter-class>com.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
结果显而易见,从前端竟然获取不到中文的参数了,感觉解决问题的路上越走越远了…
于是重新回顾整个请求流程:
(1)浏览器发送数据时,前端页面用了chatset=utf-8使用的utf-8。
(2)服务器解析浏览器发送的数据时,post提交已经通过过滤器设置为utf-8。
(3)服务器在返回数据时,前端整个文件编码以及内部编码设置的都是utf-8,
response.setContentType("text/html;charset=utf-8");
<%@page contentType="text/html;charset=gbk" pageEncoding="utf-8"%>
(4)最后是浏览器解析服务器返回的数据时,使用的也是utf-8
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
从请求到返回都使用了统一的UTF-8的编码,没道理这样了还是乱码。
于是换一种思路想,这次想着是不是参数返回格式不对呢,于是,把返回参数改成了JSON格式试了试,map转json倒也可以。但这就跟前端参数接收冲突了,如果再改前端获取的方式,那么多展示项,内心真的十分抗拒,太麻烦,懒的改,最后这个方式也Pass了(幸好有点懒)。
那是不是微信内置浏览器的锅呢?
于是打开微信web开发者工具,模拟本地请求。显示请求竟然丢失中文参数,于是重新给url请求参数做了编码处理,参数拆分开来,每个参数进行encode编码尝试 (这次并没有觉得麻烦,直觉这就是解决方案),如下:
URLEncoder.encode(pmap.get("namexx"),"utf-8")
再次请求,竟然成功了。
部署到服务器上,测试跑一跑发现问题竟然还在…。项目毕竟要线上用,本地再好使也没用。
…
于是重新定位到问题不在后台前端编码设置上,在服务器上。
连上服务器看看设置,原来的http请求设置了URIEncoding=“UTF-8”,但是当前使用已经更改为https,但是在服务器上的Tomcat配置并没有设置URIEncoding编码。
回看这次解决问题的过程,一开始轻视问题,之后盲目的经验主义定位问题,最后转换角度才找到问题原因。
如果最开始直接微信开发者工具跑一下,区分两种请求的不同,要能省下许多时间。
不过,这个过程中又把Unicode编码原理过一遍也算温故知新了吧。。。
以上