前言:
作为一名开发人员,你的开发生涯没有遇到各种各样的乱码问题,一定是不完整的。经历过各种乱码的人,对项目各种数据的传输流程也一定会有比较深刻的理解。有经验的程序员,解决乱码问题是很easy的,而小白就难多了。博主也是经历这个阶段过来的,以前懒不写总结,现在慢慢补吧,遇到就写一下。
习惯把总结写在最前面,毕竟心急火燎的人是要解决问题的,但愿对你有帮助。
总结:
核心:
保证数据不论在请求、传递、处理、回传过程中均采用统一编码格式,是不会产生乱码的。
1.form表单提交的内容浏览器会自动帮助编码,带中文参数的链接是不会转码的,如果不设置web容器的URI,不在代码上强转,请在请求前进行编码
URLEncoding.encode(str,"UTF-8")
2.form表单的get请求,在服务器是一定会通过ISO-8859-1的方式进行解码,若不想get请求产生问题,可以在后台接收参数时进行手工解码
new String(request.getParameter("name").getBytes("iso-8859-1"),"客户端编码方式");
若觉得繁琐,建议设置tomcat/conf/server.xml里的参数(web容器有多个不同项目慎选)
URIEncoding="utf-8" 或 useBodyEncodingForURI="true"
3.form表单的post请求乱码,请保证前端有pageEncoding和contentType,请求解码时会根据这个解码,若到servlet产生乱码,设置解码格式,保证前后台一致。
request.setCharacterEncoding("UTF-8");
正文:
本文的详述是基于web应用,那么自然就是使用的URL请求了。URL是从简单上说,就是一个字符串,从深入说,一段URL包含了众多信息,如通信协议、主机域名、处理port、应用路径、路径參数页面片段等等。
然后URL请求也分Post与Get方式,它们会首先传递到Web容器,以Tomcat为例,它默认的是以ISO-8859-1的编码来对我们传参进行解码。如果你的Tomcat只跑一个项目,那么建议直接更改Tomcat/config/server.xml,对其加上URIEncoding=“utf-8”。
经过Web容器后,请求会继续到Servlet中,如果你在web.xml中配置有拦截器那么可以在这里进行转码统一,之后后直接转到项目对应绑定的action上。
本文将模拟操作从JSP页面发起提交到后台,并成功接收返回数据的过程,本文以UTF-8为标准字符集,中间会有几个环节引起乱码问题,会做说明。
提交页面A:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>这是提交页面A</title>
</head>
<body>
<form action="${path}/web/proOrderIndex">
<input type="text" name="productData"/>
<input type="submit" value="提交" />
</form>
</body>
</html>
请求的编码是由浏览器发出的,我们重点关注方向应该在浏览器对URL的转码格式,与server对URL的解码格式上。
下面来说一下浏览器对URL的转码与解析:
http://192.168.1.1:8080/order/proOrderIndex.action
URL的Path部分(例如:http://192.168.1.1),这一段是标准使用UTF-8格式转码,浏览器通用,而后面的param部分是我们需要传递的值,重点就是这部分的转码与解析问题。
使用Get方法请求server信息时,依据HTTP协议规定,Request包是没有请求体的,那么Get请求只以拼接的方式绑定了参数,是如何携带的编码规则呢,我看过不少帖子说是根据当前页面的编码规则,这里博主未做测试,不确定,因为有时候Get请求乱码,而Post请求不乱码。(忘了从哪里看到写的一篇文章,讲会根据浏览器的默认编码格式对Get请求参数处理)
而使用Post请求时,浏览器会根据页面meta的编码来转码 Request body中的参数,之后请求会到后台,根据使用的不同框架servlet再针对指定编码进行转码。
回归正题:
1、get请求乱码
回应上部分讲述的URL与浏览器URI问题,以Tomcat为例,前端发起get请求携带中文参数,目前最新的浏览器URI编码统一使用的是UTF-8,那么我们出发的地方是定义了编码格式的,之后请求到Tomcat了,对URL进行解码,它本身也是有URI标准的,默认的是ISO-8859-1。好了,到Tomcat/conf/server.xml,添加上指定解码 URIEncoding=“utf-8”。
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
不过如果Tomcat服务器上同时在跑多个项目,并且有不同编码格式的,那么改全局的方式,并不合理了。
对于get请求来说,value值都是ASCII类型,如果非ASCII则会变成乱码,上述更改web容器的编码格式可以解决get提交的问题,或者通过自己知道的客户端发起提交时是什么编码格式,将其进行指定解码,则可以得到正确的value。
new String(request.getParameter("name").getBytes("iso-8859-1"),"客户端编码方式");
2、post请求乱码
对于post请求,浏览器发起请求会携带当前页面的contentType,根据meta转码后,到servlet层,你需要告诉它你指定的到底是什么编码格式,使用对应的编码格式解码,就得到正确数据,否则就产生乱码,在页面上,应尽量加上下面的这段标签。
contentType="text/html; charset=utf-8" pageEncoding="utf-8"
博主曾经看到过一篇帖子,讲的是post请求乱码的求救,一直没有解决,并且在后台设置过滤器、request编码都试过不行,反而通过上述(get请求2方法)的强转方式获取到了正确的值,这是为什么?
原因就是在页面form表单发起提交时编码格式并不是自己预期的(假定UTF-8),经过web容器到servlet解码的格式是根据自己预期的解码,出入不一致,产生了乱码。
针对于post提交,相对于简单,因为post会携带页面编码格式,那么我们直接到后台做对应的转码即可。
这里在自己的项目中添加上一个自定义监听,然后对servlet的request请求获取并设置指定格式转码。(如下,正好提到,直接顺便说明一下从server到前端乱码设置response编码的方法)
//请求内容转码
resquest.setCharacterEncoding("UTF-8");
//回传告诉浏览器展示编码
response.setContentType("text/html;charset=UTF-8");
附加上详细的处理:(spring可以直接配置,不需要写代码)
web.xml添加自定义处理
<filter>
<filter-name>WebFilter</filter-name>
<filter-class>com.daowua.platform.util.WebFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>WebFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
具体对象WebFilter
package com.daowua.platform.util;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class WebFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest resquest, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//设置请求转码格式
resquest.setCharacterEncoding("UTF-8");
//设置response回传页面编码格式
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(resquest, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}