最近作一个项目,前台传到后台的数据是乱码。看着代码应该是正确的,可是就是有问题,而后请教了旁边的老司机才找到问题是什么。话很少说,下面是模拟情景的代码,其实也很简单,前台一个form表单,post 方法,而后传一个中文字符串到servlet。 若是第一次调用request,不是设置字符编 码(req.setCharacterEncoding("utf-8");)而是调用其余的request 方法,那么设置的字符编码不会成功。html
前端模板:前端
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="/post" method="post"> 用户名<input type="text" name="name"> <input type="submit" value="提交"> </form> </body> </html>
Java 代码java
package cn.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/post") public class TestPost extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String cmd = req.getParameter("cmd"); list(req, resp); } public void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String name = null; if (req.getParameter("name") != null && !"".equals(req.getParameter("name"))) { name = req.getParameter("name"); System.out.println("name-------------------------->>>:" + name); } } }
如上代码:request 首先调用 req.getParameter("cmd");而后再是 req.setCharacterEncoding("utf-8");出现的缘由是request 在传入的时候若是不设置req格式,在第一次调用req 的时候tomcat 会自动的给req 增长字符格式 ,后面再设置 req.setCharacterEncoding("utf-8")就会无效。ajax
要修改就很简单了①:把form 表单改成get 数据库
②: req.setCharacterEncoding("utf-8"); 声明在第一行,或者filter 里面作字符处理浏览器
③: tomcat
String name = req.getParameter("name");服务器
byte[] nameBytes = name.getBytes("ISO-8859-1");框架
name = new String(nameBytes,"utf-8");ide
在写一个小小的表单提交功能的时候,出现了乱码,很奇怪request上来的参数所有是乱码,而从数据库查询出来的中文显示到页面正常,锁定确定是request对象那里出了问题。后来通过排查,发现是我封装的框架中出了问题,总结为在setCharacterEncoding方法以前,调用了getParameter方法,致使字符集改变失败。没看过Tomcat实现Servlet的源码,貌似是一旦调用getParameter方法Request的参数就会所有被解析,从而再调用setCharacterEncoding就无效了。
其实编码问题本质仍是两点:
那么咱们就从这两点入手解析。
在点击提交表单的那一刻,浏览器把表单内容封装成一个Http请求,数据经过a=1&b=2
这样的形式直接请求服务器,表单值会被浏览器最一次urlencode,对于不一样的请求方式编码不一样:
浏览器会读取页面的编码(页面编码会在Content-type头中体现),用此编码对表单值作urlencode,那么到服务器的编码方式就是你Content-Type里的编码。不少经过JS提交表单为了规避浏览器的urlencode带来的编码混淆,会对数据首先作一次urlencode,这样在服务器上作一次urldecode既可(由于js作完urlencode后内容为ASCII字符,因此这样的字符不管浏览器用什么编码解码出来都是同样的)
在Jquery中AJAX请求所有使用utf8编码封装请求,若是你的页面和项目用的非utf8编码,必定会出现乱码
这种状况就比较复杂,不一样的浏览器编码也不相同。Chrome之类的浏览器默认使用utf8编码(urlencode),而IE则使用GBK(死变态IE!!!)。
对于服务器端我在此只讨论Servlet。
对于Get请求,有两种方式解码:
String name = new String(request.getParameter("name").getBytes("iso-8859-1"),"GBK"));
第一个编码就是你Servlet容器(例如Tomcat)里设置的编码,默认iso-8859-1,第二个参数就是你浏览器使用的编码格式。若是你用表单提交,那这个编码就是页面的编码(Content-Type里的charset=XXX),若是你直接用浏览器地址栏里敲,恭喜你,你得判断userAgent来使用不一样编码了。这也是我为啥不提倡第一种方式,由于它遇到浏览器直接敲出来的参数就很是不灵活。至于为何要使用getBytes("iso-8859-1"),是由于在你浏览器用某种编码后,Servlet容器自做多情给你用iso-8859-1解码了一下,若是你设置了URIEncoding="UTF-8"它就会用utf8给你解码,运气好你浏览器用的也是这种编码,那解出来就直接用了,因此在ISO-8859-1的状况下你得再“原路返回”到二进制,从新用正确的编码解码一下。
Post请求就比较简单一点了,一样你可使用Get请求中的方法2来解决,不过比较麻烦,这时候咱们就可使用Servlet里的方法request.setCharacterEncoding方法设置你的解码类型,例如你的页面编码是utf8,表单则urlencode成utf8了,那么你在调用getParameter方法以前(记住,必定要以前!!在第一次调用getParameter以前!)使用setCharacterEncoding方法。 Ajax请求同理。
响应也是相同道理,这回轮到服务器作编码,浏览器作解码。只须要设置response.setCharacterEncoding,就会自动在响应头的Content-Type中加入charset=XXX,返回的内容就能够被正常解析啦~
我想我说的相对比较清楚了,网上不少解决乱码的帖子都只是讲你加上某句代码就会解决,这样是不科学的,必定也要知道原理,也要知道每句代码背后作了哪些工做。其实咱们在操做HttpServlet对象的时候,本质上是对Http头的一些信息作修改。