参考:
- 客户端编码与服务器解码全过程_gaoge19861207的专栏-CSDN博客
- 深入分析 web 请求响应中的编码问题_weweeeeeeee的博客-CSDN博客
- Tomcat web 编解码过程_zhangbinalan的专栏-CSDN博客
- 关于 tomcat7 和 tomcat8 服务器编码的解释_LawssssCat的博客-CSDN博客
- java web 一次请求编码设置的过程 - 人生已是如此的艰难 - 博客园
原始代码:使用Tomcat7.x服务器
客户端(使用了谷歌验证码):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
......
<form action="http://localhost:8080/tmp/registServlet" method="get">
用户名:<input type="text" name="username"/><br/>
验证码:<input type="text" style="width: 60px;" name="code"/>
<img src="http://localhost:8080/tmp/kaptcha.jpg" id="code_img" alt="" style="width: 100px; height: 28px;"/>
<input type="submit" value="登录">
</form>
servlet程序:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Session中的验证码
String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
//删除Session中的验证码
request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
String code = request.getParameter("code");
String username = request.getParameter("username");
if(token != null && token.equalsIgnoreCase(code)){
System.out.println("保存到数据库:" + username);
response.sendRedirect(request.getContextPath() + "/ok.jsp");
}else{
System.out.println("请不要重复提交表单");
}
}
终端输出:
知识回顾:
-
-
tomcat7中关于connector的编码默认为" iso8859-1 "; tomcat8中connector的编码默认为" utf-8 "
-
所以 tomcat7默认的解码方式是:输入ISO8859-1的编码方式进行解码
-
-
浏览器呈现的两种web页面:html页面和jsp页面
-
-
通过表单提交发起的请求:对于表单中的参数, 无论是 通过 get 方法(通过 URL 查询参数)还是 post 方法(通过请求体)提交,浏览器(谷歌、火狐、IE)都会根据页面的 ContentType("text/html; charset=enc") 中指定的编码对表单中的数据进行编码,然后发给服务器。
-
通过3和4可知:网页(html文件或者jsp文件)在浏览器上的解码方式 就是 当前网页的表单数据提交给服务器前进行编码的方式
-
-
jsp文件本身的编码:pageEncoding;服务器发送给客户端浏览器时的内容编码(服务器通过响应头来通知客户端以那种编码形式来进行解码呈现web页面(jsp文件/html页面)的内容): contentType 的 charset
-
contentType 里的 charset="utf-8" ,指的是此web文件输出到浏览器的输出方式为 utf-8 。在这个过程中,一个 JSP 的源文件需要经过三个阶段,两次编码,才能完成一次完整的输出。(服务器响应到客户端的过程)
-
第三阶段:从服务器到浏览器,这在一过程中用到的指令是contentType。服务器载入和执行由第二阶段生成出来JAVA二进制码,输出的结果,也就是在客户端可见到的结果,在这次输出过程中,由contentType属性中的charset来指定,将UTF8形式的二进制码以charset的编码形式来输出。 如果没有人为设定,则默认的是ISO-8859-1的形式 。---- java web 一次请求编码设置的过程 - 人生已是如此的艰难 - 博客园
-
由4.可知 如果没有人为设定 contentType属性中的charset,客户端将以ISO-8859-1的编码方式对表单数据进行编码
-
-
-
-
【 客户端发送的数据在请求行中】
-
-
【 客户端发送的数据在请求体中】
-
-
对英文字符来说UTF-8编码和ISO-8859-1编码的效果相同
-
UTF-8编码的格式:一个汉字来三个字节构成,每一个字节会转换成 16进制的编码 ,同时添加上%号
GET乱码原因分析:
GET请求的全过程:
-
客户端浏览器地址栏中向服务器发送请求: http: 服务器地址: port/ 工程名 /regist.jsp
-
其中 Regist.jsp中:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
-
浏览器中呈现以utf-8编码方式解码的regist.jsp文件
-
GET方式提交表单,提交表单时表单数据会按照utf-8 来编码数据。因为是GET 方式,这些数据(已经编码好成为字节了)位于http请求行中。
-
将http请求发送到服务器
-
服务端收到客户端的 HTTP 请求, 中间件/应用服务器 会针对每一次请求分别创建一个 request 对象和 response 对象。
-
request 对象是 服务器端 操作 客户端发送过来的数据 的容器。
-
response 对象是 服务器端 操作 服务端发出的数据 的容器。
-
-
Tomcat7.x中默认的编码方式是ISO8859-1,所以也默认使用ISO8859-1对GET请求行中的数据进行解码
-
得到 ISO8859-1解码后的乱码
GET乱码解决方案:
-
因为原数据的编码方式是utf-8,并且被使用ISO8859-1编码方式进行了解码,所以先使用ISO8859-1对乱码进行编码,得到字节数组,然后再使用UTF-8对字节数据进行解码即可。
String username = request.getParameter("username");//乱码
username = new String(username.getBytes("ISO8859-1"),"UTF-8");//没有乱码
POST乱码原因分析:
因为:
通过表单提交发起的请求:对于表单中的参数,
无论是
通过
get
方法(通过
URL
查询参数)
还是
post
方法(通过请求体)提交,浏览器(谷歌、火狐、IE)都会根据页面的
ContentType("text/html;
charset=enc")
中指定的编码
对表单中的数据进行编码,然后发给服务器。
所以:post请求体中的数据也是通过UTF-8进行编码后将http请求发送给服务器,然后Tomcat7.x服务器使用默认的ISO8859-1编码方式进行解码,从而导致中文乱码问题。
POST乱码解决方案:
-
仍可以通过GET中的解决方式解决POST乱码,即:
String username = request.getParameter("username");//乱码
username = new String(username.getBytes("ISO8859-1"),"UTF-8");//没有乱码
2. 因为:request 对象是
服务器端 操作 客户端发送过来的数据 的容器。所以可以通过改变request对象的请求体中的编码方式(从而改变了服务器对request对象的请求体中的解码方式),使得Tomcat7.x服务器对request对象的请求体中的默认解码方式变为指定编码的解码方式。
request.setCharacterEncoding("UTF-8");//在获取请求参数前使用
-
注:因为改变的是request对象的请求体中的编码方式,所以对GET的乱码无效。