在前面使用SpringMVC写登录验证页面时,如果用户名是中文可能会出现服务端获取为乱码的情况,另外当提交方式为get或者post时,乱码的情况也不太一样,因此这里小小记录一下中文乱码原因及如何处理。
乱码问题,本质上来说就是数据在传输的过程中,浏览器和服务端编解码的不同导致出现乱码,本文将从浏览器和服务器的角度分析编码,理解登录时中文传送到服务端乱码的情况,其实一般情况下登录时浏览器默认按照utf-8来编码,但是到了服务器是按照ISO-8859-1即西欧码表来解码,从而导致服务端接受的是乱码。
测试准备
测试在上文使用SpringMVC实现登录的基础上,添加一个Controller和JSP专门用来测试提交数据到服务端,JSP接下来接受服务端的数据并呈现。
JSP如下,其中form表单action地址根据测试需要进行调整,method属性区分post和get,使用ModelMap返回值时,JSP写一个div接收。
1 <%@page pageEncoding="utf-8" contentType="text/html;charset=utf-8"%> 2 <html> 3 <body> 4 <!-- 测试编码,action根据测试地址发生调整 --> 5 <form action="sendWithModelMapPost.do" method="post"> 6 <input type="text" name="name"/> 7 <input type="text" name ="age"/> 8 <input type="submit" value="提交"/> 9 </form> 10 <!-- 得到服务端返回的值 --> 11 <div> 12 <div>${returnName}</div> 13 <div>${returnAge }</div> 14 </div> 15 </body> 16 </html>
pageEncoding和contentType
JSP中会设置pageEncoding="utf-8" contentType="text/html;charset=utf-8",这两个有什么区别呢,pageEncoding就是jsp编译成java文件以及向服务端传值的编码,因此当向服务端提交数据时,会按照这个这个设置来编码。contentType就是页面展示以及获取服务端传递过来的值的编码,如果我们将utf-8改成西欧码表iso-8859-1,会发现"提交"按钮的中文无法正常显示。
另外还需要了解的是,iso-8859-1是无法表示中文的,因为其只有1个字节,中文需要用GBK、gb2312、utf-8、unicode等才能表示,因此如果要提交中文,浏览器需要使用这些才可以,本文使用utf-8。
POST提交
post提交是最常用的一种提交方式,其可以隐藏参数,向服务器发送数据一般会发送两次,第一次确认可以连接,当服务端返回100(continue)状态码后才将数据发送过去。
(1)使用SpringMVC提供的ModelMap返回数据
1 //使用ModelMap返回数据-post 2 @RequestMapping("/sendWithModelMapPost.do") 3 public String sendPost(ModelMap mm,HttpServletRequest request) throws UnsupportedEncodingException { 4 //获取服务端获取页面请求默认编码格式 5 String defaultRequestEncoding=request.getCharacterEncoding(); 6 System.out.println("服务端request默认编码格式为:"+defaultRequestEncoding); 7 //设置服务端获取页面请求编码格式为utf-8 8 request.setCharacterEncoding("utf-8"); 9 System.out.println("服务端request修改编码格式为:"+request.getCharacterEncoding()); 10 String name=request.getParameter("name"); 11 System.out.println(name); 12 String age=request.getParameter("age"); 13 System.out.println(age); 14 //使用ModelMap返回数据 15 mm.addAttribute("returnName", name); 16 mm.addAttribute("returnAge", age); 17 return "codeTest"; 18 }
提交数据测试,页面可以正常返回提交的数据
控制台情况,可以看出服务端从浏览器接受数据时,默认是没有编码的,需要指定和浏览器一样的编码utf-8才能正确解码,另外发送数据到浏览器的编码不需要指定也可以正确返回,是因为SpringMVC的帮我们设定了编码格式为utf-8。
(2)使用PrintWriter返回数据
1 //使用PrintWriter返回数据-post 2 @RequestMapping("/sendWithPrintWriterPost.do") 3 public void sendPost(HttpServletRequest request,HttpServletResponse response) throws IOException { 4 String defaultRequestEncoding=request.getCharacterEncoding(); 5 System.out.println("服务端request默认编码格式为:"+defaultRequestEncoding); 6 request.setCharacterEncoding("utf-8"); 7 System.out.println("服务端request修改编码格式为:"+request.getCharacterEncoding()); 8 String returnName=request.getParameter("name"); 9 System.out.println(returnName); 10 String returnAge=request.getParameter("age"); 11 System.out.println(returnAge); 12 String defaultResponseEncoding=response.getCharacterEncoding(); 13 System.out.println("服务端response默认编码格式为:"+defaultResponseEncoding); 14 //设置response编码,如下两个一起使用,等效于response.setContentType("text/html;charset=UTF-8"); 15 response.setContentType("text/html"); 16 response.setCharacterEncoding("utf-8"); 17 //response.setContentType("text/html;charset=UTF-8"); 18 System.out.println("服务端response修改编码格式为:"+response.getCharacterEncoding()); 19 PrintWriter pw=response.getWriter(); 20 pw.println(returnName); 21 pw.println(returnAge); 22 pw.flush(); 23 }
提交跟上面一样的数据,如果不设置request编码和response编码,发现无法正确显示。
查看控制台,发现服务端无法正确解码,如果不指定request的编码默认就是null,并且向浏览器发送数据的编码,默认使用的是iso-8859-1,这样页面就显示乱码了。
将request指定编码和页面发送数据一样的编码格式utf-8,并且将response的编码也指定为contentType一样的编码utf-8 ,这样就都统一为utf-8,就不会显示乱码了。
GET提交
GET提交将显示提交的参数,各大浏览器对提交的url长度有限制,一般不能超过2k个字节,其向服务器发送数据只需要一次。
(1)使用SpringMVC提供的ModelMap返回数据
1 //使用ModelMap返回数据-get 2 @RequestMapping("/sendWithModelMapGet.do") 3 public String sendGet(ModelMap mm,HttpServletRequest request) throws UnsupportedEncodingException { 4 //获取服务端获取页面请求默认编码格式 5 String defaultRequestEncoding=request.getCharacterEncoding(); 6 System.out.println("服务端request默认编码格式为:"+defaultRequestEncoding); 7 //设置服务端获取页面请求编码格式为utf-8 8 request.setCharacterEncoding("utf-8"); 9 System.out.println("服务端request修改编码格式为:"+request.getCharacterEncoding()); 10 String name=request.getParameter("name"); 11 System.out.println(name); 12 String age=request.getParameter("age"); 13 System.out.println(age); 14 //使用ModelMap返回数据 15 mm.addAttribute("returnName", name); 16 mm.addAttribute("returnAge", age); 17 return "codeTest"; 18 }
测试结果
控制台情况,也需要指定request的编码为utf-8,否则获取浏览器发送过来的数据解码时肯定会出现异常变成乱码。
(2)使用PrintWriter返回数据
1 //使用PrintWriter返回数据-get 2 @RequestMapping("/sendWithPrintWriterGet.do") 3 public void sendGet(HttpServletRequest request,HttpServletResponse response) throws IOException { 4 String defaultRequestEncoding=request.getCharacterEncoding(); 5 System.out.println("服务端request默认编码格式为:"+defaultRequestEncoding); 6 request.setCharacterEncoding("utf-8"); 7 System.out.println("服务端request修改编码格式为:"+request.getCharacterEncoding()); 8 String returnName=request.getParameter("name"); 9 System.out.println(returnName); 10 String returnAge=request.getParameter("age"); 11 System.out.println(returnAge); 12 String defaultResponseEncoding=response.getCharacterEncoding(); 13 System.out.println("服务端response默认编码格式为:"+defaultResponseEncoding); 14 //设置response编码,如下两个一起使用,等效于response.setContentType("text/html;charset=UTF-8"); 15 response.setContentType("text/html"); 16 response.setCharacterEncoding("utf-8"); 17 //response.setContentType("text/html;charset=UTF-8"); 18 System.out.println("服务端response修改编码格式为:"+response.getCharacterEncoding()); 19 PrintWriter pw=response.getWriter(); 20 pw.println(returnName); 21 pw.println(returnAge); 22 pw.flush(); 23 }
控制台情况,也是将request和response的编码都设定为了utf-8,这样就不会导致乱码。
另外有博文称修改tomcat配置文件server.xml中如下内容可以让编码默认都变成utf-8,但是测试了好几次没有效果,后续再测试,先放这里。
1 <Connector URIEncoding="utf-8" useBodyEncodingForURI="true" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
过滤器中设置
另外还有一种避免乱码的方法,就是在过滤器中设置编码格式,这样服务端不需要每个请求方法里都设定request和response的编码,默认都按照过滤器的编码来处理。web.xml中添加过滤器配置如下,其中forceEncoding设置为true代表强制按照过滤器编码来处理,方法里设置的无效。
1 <!-- 配置过滤器,统一编码格式,只对post有效--> 2 <filter> 3 <filter-name>myFilter</filter-name> 4 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 5 <!-- 添加下面设置发现request的编码格式变成了utf-8 --> 6 <init-param> 7 <param-name>encoding</param-name> 8 <param-value>UTF-8</param-value> 9 </init-param> 10 <!-- 添加下面设置发现response的编码格式也设置成了utf-8 --> 11 <init-param> 12 <param-name>forceEncoding</param-name> 13 <param-value>true</param-value> 14 </init-param> 15 </filter> 16 <filter-mapping> 17 <filter-name>myFilter</filter-name> 18 <url-pattern>/*</url-pattern> 19 </filter-mapping>
测试发现,无论GET还是POST请求都有效果,下面是get请求,并且方法里不设定编码格式的结果。
控制台情况,发现默认的编码格式全部变成了utf-8。
总结
(1)中文乱码的出现本质上就是浏览器和服务器编码解码的方式不统一造成,浏览器默认使用utf-8提交数据,服务器默认使用iso-8859-1来发送数据,不管是get请求还是post请求,要解决乱码需要统一编码格式。
(3)过滤器编码设置可以将服务端request接受参数和response响应参数默认编码都设定为一样
参考博文
(1)https://www.cnblogs.com/logsharing/p/8448446.html GET和POST区别的通俗解释
(2)https://blog.csdn.net/u013381397/article/details/78028865 GET编码在tomcat中设定
(3)https://www.cnblogs.com/zengyufei/p/4456472.html
(4)https://www.cnblogs.com/youngchaolin/p/11354307.html 登录案例