您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

JAVA WEB 笔记--中文乱码

2026/2/8 1:20:06发布13次查看
java web 乱码问题解析乱码原因在java web开发过程中,经常遇到乱码的问题,造成乱码的原因,概括起来就是对字符编码和解码的方式不匹配。
既然乱码的原因是字符编码与解码的方式不匹配,那么为什么我们一定要对字符进行编码,不编码可不可以呢?这是因为在计算机中存储数据的基本单位是1个字节,即8个bit,那么它所能表达的字符的最多有28=256个,而在我们现实社会中存在的字符(汉字、英文、其他文字等等)远远多余这个数字,所以为了解决字符与字节的矛盾,对字符进行编码处理才能存储在计算机中。
编码与解码在计算机中常见的编码方式有ascii、iso-8859-1、gb2312、utf-16、utf-8几种编码方式。
ascii码是使用一个字节的低7位来表示的,所以共能表达的字符最多有27=128个。iso-8859-1是iso组织基于ascii码的基础上扩展来的,兼容ascii码,涵盖了大多数西欧字符。iso8859-1使用一个字节来表示,所以其能表达的字符最多有256个。gb2312,采用了双字节编码,编码范围是a1-f7,其中a1-a9是符号区,b0-f7是汉字区,包含6763个汉字。gbk是为了扩展gb2312编码,并加入了更多的汉字,总能表达的汉字有21003个。utf-16是采用定长的编码方式,无论什么字符都采用2个字节进行表示,这也是java内存中字符的存储格式。与utf-16相反,utf-8采用了变长的编码方式,不同的类型的字符可以由1-6个字节组成。
 下面以字符串“日向雏田”来看一下在计算机中不同编码方式的编码,如下图。
乱码分析与解决对于java web中乱码问题,我们划分位请求导致的乱码和响应导致的乱码,对于不同的乱码我们要分析其乱码原因,即字符编码的方式是什么,解码的方式是什么。
对于由于请求导致的乱码我们要分析http请求,查看其编码方式,由于http请求分为get请求和post请求,我们接下来分别对其进行讨论。
对于get请求,是浏览器默认的请求方式,和表单提交时设置为“get”时的提交方式。我们通过火狐浏览器我们查看其具体内容如下:
地址栏为:
请求内容为:
通过上面请求我们可以看到,get请求中查询字符串放在了请求行中存放,发送到web服务器中,通过“日向雏田”编码我们可以看到,浏览器对该字符串采用的编码方式为“utf-8”。
查看服务器代码我们可以看到乱码(如下图),这是因为服务器在接受到该字符串编码后的数据默认通过iso-8859-1的方式进行解码,所以造成了编码与解码的方式不统一。
解决方案如下:
首先获取字符串user解码前的编码,然后指定该字符串的编码方式,如下图:
解决方案示意图如下:
在java web开发过程中,我们在超链接中传递参数,经常遇到中文的情况。对此情况下,我们需要对中文进行编码,我们可以设置为utf-8,解码方案同上。
<a href="${pagecontext.request.contextpath}/test?user=<%=urlencoder.encode("日向雏田", "utf-8")%>">点击</a>
对于post请求,是表单提交时设置为“post”时的提交方式。我们通过火狐浏览器我们查看其具体内容如下:
地址栏及其页面为:
post请求内容为:
由上图我们可以知道,在post请求中,将请求内容直接放在请求体中发送给web服务器,编码方式为“utf-8”。
在此响应servlet中,dopost方法体如下:
public void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string user=request.getparameter("user"); system.out.println(user);//输出为日向雏田 }
此处乱码的原因依然时在代码getparameter(“user”)时,web服务器采用默认的解码方案“iso-8859-1”进行解码,导致了编码与解码方案的不同意,解决方案可以采用get请求乱码的解决方案,但是还有一种更为简单的解决方案,直接指定方法体的编码/解码方案为“utf-8”。方案如下。
public void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { response.setcharacterencoding("utf-8");//设置请求体的编码/解码方案为utf-8 但是请求行的编码解码方案不会受影响 string user=request.getparameter("user"); system.out.println(user);//输出为日向雏田 }
以上对于请求导致的乱码情况分析完毕。
在影响导致的乱码中,web服务器会将响应的内容写入响应体中,返回给客户端并不会涉及到状态行中的情况。如向浏览器输出”helloworld“其响应如下图所说。
对于响应导致的乱码我们不得不涉及到四个方法,如下:
response.setheader("content-type", "text/html;cahrset=utf-8");//设置发送到客户端的响应的内容类型和响应内容的编码类型(响应体的编码类型) response.setcharacterencoding("utf-8");//设置响应体的编码类型 response.getwriter(); //获取响应的输出字符流  response.getoutputstream();  //获取响应的输出字节流
对于设置响应体的编码类型,如response.setheader("content-type", "text/html;cahrset=utf-8");与response.setcharacterencoding("utf-8");这2个方法设置的编码方式等效,若没有设置响应体的编码方式,则默认为iso-8859-1,而且后面设置响应体字符的编码方式会迭代前面的设置编码的方式。这两个方法均在getwriter方法前有效,在getwriter方法设置编码的方法会无效。
但是这2个方法却有点不同,即setheader("content-type", "text/html;cahrset=utf-8")这个方法浏览器会自动采用该响应体的编码方式进行解码,而setcharacterencoding()该方法并不是所有的浏览器都会采用该方法的编码方式进行解码,下面对这2个方法进行测试,效果如下:
public void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { response.setheader("content-type", "text/html;charset=utf-8"); response.getwriter().write("日向雏田"); }
public void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { response.setcharacterencoding("utf-8"); response.getwriter().write("日向雏田"); }
从上面可以看到第一个方法对于浏览器来说,支持的较好,提倡采用第一种方法设置响应体的字符编码方式。
对于获取响应字符输出流的方法,如果在此之前没有设置响应体的编码方式,那么默认为null,即iso-8859-1方式进行编码。而且后面设置的编码方式会覆盖前面设置的编码方式。在getwriter()方法之后设置的编码无效。
对于获取响应输出字节流,我们在输出字符串时,我们需要设置字符串的编码方式如果没有那么默认iso-8859-1。
对于前面2个输出流,由于只有一个输出缓存,所以这两个方法互斥。
以上,为了保证响应无乱码,需要保证字符编码和解码方法的统一,方案如下:
public void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { // 方案1 // response.setheader("content-type", "text/html;charset=utf-8"); // response.getwriter().write("日向雏田"); // 方案2 // response.getoutputstream().write("日向雏田".getbytes("utf-8")); // 方案1,2互斥 }
此外在java web开发过程中,我们还会遇到当进行文件下载时,中文文件名导致的问题,如下图所示:
public void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string realpath=this.getservletcontext().getrealpath("/src/日向雏田.jpg"); string filename=realpath.substring(realpath.lastindexof('\\')+1); response.setheader("content-disposition", "attachment;filename="+filename); inputstream is=new fileinputstream(new file(realpath)); outputstream os=response.getoutputstream(); byte[] buff=new byte[1024]; int len=0; while((len=is.read(buff))>0){ os.write(buff, 0, len); } os.close(); is.close(); }
采用火狐浏览器进行测试,查看页面效果,及其响应结果如下:
经过查看响应头分析,下载文件名存放在响应头中,且对于中文文字没有采用utf-8、utf-16、gbk等等能识别中文的编码,那么对于中文文件名导致采用哪种编码方式呢?查看ref 7578得知,在此处采用ascii编码,但是ref规定,如果不可避免的要使用非ascii码的字符,程序员应该均匀的使用utf-8,来最小化交互操作的问题。
所以,解决方案就是把文件名编码成utf-8,传递给响应头,浏览器(部分)默认对该文件名进行utf-8解码处理。
public void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string realpath=this.getservletcontext().getrealpath("/src/日向雏田.jpg"); string filename=realpath.substring(realpath.lastindexof('\\')+1); string utf_8name=urlencoder.encode(filename,"utf-8");//解决方案 response.setheader("content-disposition", "attachment;filename="+utf_8name); inputstream is=new fileinputstream(new file(realpath)); outputstream os=response.getoutputstream(); byte[] buff=new byte[1024]; int len=0; while((len=is.read(buff))>0){ os.write(buff, 0, len); } os.close(); is.close(); }
效果如下:其中火狐浏览器并没有对其解码
以上就是java web 笔记--中文乱码的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product