浏览器和服务器之间如何编码解码
1.浏览器和服务器之间编码解码的过程
从上图可以看出,有两个过程是我们可以干预设置的,只有当上面两个过程编码格式相同的时候,才不会出现乱码!
2.详细剖析get方式编码解码及乱码方式
对于GET方式而言:它是将数据附在URL后面进行传输的,这样就很容易出现乱码,因为值有可能传递的是非ASCII吗(HTTP协议是ASCII码传输的,建立在 TCP/IP 协议之上的应用层规范)。
首先浏览器通过指定的编码格式将页面编码传递给服务器**(这个过程可以通过在JSP文件中的pageEncoding="")**设置。此时jsp文件转换为servlet文件
服务器再将servlet文件解析,然后通过Unicode编码成class文件(这个过程无法干预)。
服务器将回应内容通过指定的格式编码发送给浏览器,浏览器通过相应的解码方式解析回应的内容1(这个过程也是可以通过设置的Content-Type,或者response.setContentType())
contentType="text/html;charset=UTF-8"1的作用是指定对服务器响应进行重新编码的编码 (也就是说服务器将内容编码响应给浏览器以及浏览器解析内容显示都是使用这个编码)。
pageEncoding=“UTF-8” 是将jsp编译成servlet时的编码
例子:
encoding.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<form action="${pageContext.request.contextPath}/EncodingServlet" method="get">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
EncodingServlet
String name=request.getParameter("name");
System.out.println(name);
response.getWriter().write(response.getCharacterEncoding());
response.getWriter().write(name);
输入:但是
结果:Console:但是
页面:ISO-8859-1 但是
结果分析:在jsp文件中contentType和pageEncoding都设置了utf-8为什么在页面还是会出现乱码而且编码格式?
console输出"但是"说明服务器是以utf-8格式编码class文件的,而页面输出乱码说明浏览器解析的时候并没有按照UTF-8的格式解析服务器传过来的内容。
打开网页的检查工具:
Response Header:
Content-Length: 10
Date: Wed, 20 Mar 2019 07:22:05 GMT
Request Header:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Cookie: JSESSIONID=8DEF8C64D08009D3192C55C72AEA42A6
Host: localhost:8080
Referer: http://localhost:8080/LoginDemo/enconding.jsp
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36
发现无论是Response Header还是Request Header都没有Content-Type的内容,这就很奇怪了,我明明在jsp文件中设置了。在这卡了很长时间,突然想到我只是在encoding.jsp文件中设置了utf-8编码解码格式,而我在转到servlet的页面并没有设置!所以会出现在页面中输出ISO-8859-1 和乱码。
证明:
方案一:
<form action="${pageContext.request.contextPath}/result.jsp" method="get">
result.jsp
<%@ 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>Insert title here</title>
</head>
<body>
<%=response.getCharacterEncoding()%>
</body>
</html>
方案二:
<form action="${pageContext.request.contextPath}/result.jsp" method="get">
EncondingServlet
response.setContentType("text/html;charset=UTF-8");
String name=request.getParameter("name");
System.out.println(name); response.getWriter().write(response.getCharacterEncoding());
方案一:我将encoding.jsp中的form表单转到result.jsp页面输出:但是 UTF-8。
方案二:在Servlet中添加了一句话:response.setContentType(“text/html;charset=UTF-8”);作用就是jsp文件中的Content-Type。输出结果:但是 UTF-8
总结:通过上面的例子得出,只要浏览器与服务器之间的编码解码方式都设置为UTF-8一般就不会出现乱码问题!
值得注意的是一般tomcat服务器默认解码方式是ISO-8859-1,如果想要设置可以在conf文件夹中的server.xml的Connection标签设置
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
其实这里设不设置无所谓,上面已经设置了setContentType(utf8)了,并且如果你只在Connection设置了UTF-8,但是在文件中没有设置ContentType仍然会出现乱码。
2.剖析POST方式编码解码及乱码方式
对于POST方式,表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType(“text/html; charset=GBK”)中指定的编码进行对表单中的数据进行编码,然后发给服务器。在服务器端的程序中我们可以通过Request.setCharacterEncoding() 设置编码,然后通过request.getParameter获得正确的数据。
例子:和上面的相同,method=“post”
EncodingServlet.java
//post方式解决乱码
request.setCharacterEncoding("UTF-8");
总结:对于服务器端只需要设置
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
无论是get方式还是post方式都不会出现乱码,但是这种方式每当你需要取值都要设置显得很麻烦
这时可以创建过滤器来解决中文乱码问题
web.xml
<filter>
<filter-name>EncondingFilter</filter-name>
<filter-class>web.EncondingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncondingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
EncodingFilter.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request, response);
}
过滤器会过滤所有路径的请求并将其编码设置utf-8,不需要每次取值都要设置。方便很多。