MIME多用途Internet邮件扩展,最初是用于解决邮件传输系统中的数据格式问题,因为通过
HTTP协议传输的数据也有各种类型,所以,HTTP也采用MIME来标识不同的数据类型
浏览器接收到的中文字符并不是中文符号本身,而是它的某种字符集编码数据。由于同一个中文字符可以使用多种字符编码,浏览器必须使用相应的字符集编码进行显示,才能将它所接收到的中文字符的某种编码数据显示为正确的中文文字。
Servlet程序输出的中文字符在浏览器中显示为筹码的原因有两种可能:
1.Servlet程序输出给浏览器的内容不是任何一种正确的中文字符集编码;
2.浏览器网页文档时所采用的字符集编码与它所接收到的中文字符本身的字符集编码不一致。
Java程序中的字符文本在内存中是以unicode编码的形式存在的,PrintWriter对象在输出字符文本时,需要先将它们转换成其他某种字符集编码的字节数组后,再把这些字节内容写入到Servlet引擎提供的缓冲区中。
如果PrintWriter对象在转换过程中使用的字符集编码不正确,那么输出到客户端的数据就不是原始字符集编码。例如:ServletResponse对象的getWriter方法返回的PrintWriter对象默认使用ISO8859-1字符集编码进行Unicode字符串到字节数组的转换,由于ISO8859-1字符集中根本就没有包含中文字符,Unicode编码的中文字符将被转换成无效的字符编码后输出给客户端。为此,ServletResponse接口中定义了setCharacterEncoding、setContentType和setLocale等方法来指定ServletResponse.getWriter方法返回的PringWriter对象所使用的字符集编码,只有在调用ServletResponse.getWriter方法返回的PringWriter对象之前调用这些方法,它们都会对PrintWriter对象起作用。
Servlet程序输出的中文字符全部显示为问题(?)
<meta>标签的一个最常见的应用就是来设置当前页面的字符集编码
服务器端程序需要使用Content-Type头字段指定实体内容的字符集编码,以便浏览器自动调整显示网页文档内容时所采用的字符集编码。同样的道理,对于静态的HTML页面,也需要通过某种方式来将它的字符集编码信息告诉给浏览器,这就可以通过将<meta>标签的http-equiv属性设置为"Content-Type"来解决。
如果一个采用GB2312编码的中文静态网页没有使用上面的<meta>语句,那么,当用户浏览器访问了某个英文站点后再来访问这个页面,其中的中文字符很可能就会显示为乱码。这是因为浏览器访问某个英文站点的页面后,浏览器显示网页文档的字符集编码可能被该页面自动设置成了ISO8859-1,在这种情况下,除非用户将浏览器显示网页文档的字符集编码手工设置为GB2312,否则,浏览器就无法正常显示GB2312编码的中文字符。所以,在每个静态的中文HTML页面的开始处都应增加一条<meta>语句来设置页面的字符集编码,已经成为了设计html页面的指导性原则和验收标准。
由于浏览器以iso8859-1字符集编码显示当前页面内容,所以,浏览器以iso8859-1字符集编码来对Form表单内填写字符,比如“中国”进行URL编码。由于iso8859-1字符集中根本就不存在“中国“这两个字符,所以,浏览器对”中国”这两个字符进行URL编码的结果是一个混乱的数据。
ServletRequest接口中定义了一个setCharacterEncoding方法,该方法用于覆盖请求消息中的实体内容的字符集编码名称的设置。getParameter和getReader方法将读取到的实体内容从字节数组形态转换成字符串返回时,都要参照请求消息中的实体内容的字符集编码名称,所以,setCharacterEncoding方法应早于getParameter或getReader方法之前进行调用。
getParameter方法的中文问题
浏览器传递这些供ServletRequest对象的getParameter等方法读取的参数信息时,必须对其中的包括中文字符在内的特殊字符进行URL编码,这些参数是以哪种字符集编码进行的URL编码,ServletRequest对象的getParameter等方法就必须以哪种字符编码进行URL解码,这样才能返回正确的中文参数信息。ServletRequest对象的getParameter等方法以哪种字符集编码对参数信息进行URL解码,需要记住以下三种情况:
(1)对于HTTP请求消息的请求行中的URL地址后的参数,getParameter等方法进行URL解码时所采用的字符集编码在Servlet规范中没有明确规定,它由各个Servlet引擎厂商自行决定。对于这种情况,Tomcat中的ServletRequest对象的getParameter等方法默认采用ISO8859-1字符集编码进行URL解码,因此无法返回正确的中文参数信息。
(2)对于POST方式下的"application/x-www-form-urlencoded"编码格式的实体内容,getParameter等方法以ServletRequest对象的getCharacterEncoding()方法返回字符集编码对其进行URL解码。如果IE浏览器产生的HTTP请求消息中没有通过任何方式指定对实体内容进行URL编码时所采用的字符集编码,那么,Servlet引擎将无法知道请求消息中的实体内容的字符集编码,getCharacterEncoding()方法的返回值为null。对于这种情况,ServletRequest对象的getParameter等方法将使用默认的ISO8859-1字符集编码对实体内容中的参数进行URL解码,因此也将无法返回正确的中文参数信息。
(3)ServletRequest接口中定义了一个setCharacterEncoding方法来设置请求消息中的实体内容的字符集编码名称,getParameter方法将以该方法设置字符集编码对实体内容进行URL解码,所以只要使用ServletRequest.setCharacterEncoding方法设置实体内容的字符集编码为其URL编码前的字符集编码,那么getParameter方法就可以从实体内容中返回正确的中文参数信息。但是,ServletRequest.setCharacterEncoding方法设置的是请求消息中的实体内容的字符集编码名称,它只影响getParameter方法对Post方式下的"application/x-www-form-urlencoded"编码格式的实体内容进行URL解码的结果,而不能影响getParameter方法对HTTP请求消息的请求行中的URL地址后的参数进行URL解码的结果。
Servlet程序涉及从浏览器中读取输入参数和向浏览器输出字符文本这两个方面,输入时的ServletRequest.getParameter方法要将URL解码后的字节数组转换成Unicode字符串,而输出时的PringWriter.pringln方法又要将Unicode字符串转换某种字符集编码的字节数组,输入或输出时的字符编码转换问题都能造成中文乱码现象。
如果getCharacterEncoding()方法返回值为null,getParameter方法对参数值进行URL解码时直接把%XX当做一个ASCII字符来处理了,即以ISO8859-1作为字符集编码进行的URL解码,而不是以GB2312等作为字符集编码进行的URL解码。
url编码是采用前端页面设置的编码方式进行编码。解码时要还原成前端页面的编码。
简单流程:浏览器对用户的字符进行URL编码,服务器端的request对象的getParameter方法对从客户端来的数据进行URL解码,然后将解码后的字节数组转换成Unicode字符串,在服务器用PrintWriter.println方法输出时,又要将Unicode字符串转换某种字符集编码的字节数组。要注意在输出时也可能产生乱码(在servlet中),即使输入时getParameter方法进行了正确的URL解码,所以要在servlet中设置此句:
response.setContentType("text/html;charset=utf-8");
charset依具体情况而定。
注意事项:
(1)不考虑人为使用浏览器菜单修改显示页面内容时所采用的字符集编码,浏览器对Form表单中输入的内容进行URL编码时所使用的字符集编码与Form表单所在页面的字符集编码是相同的,这意味着Servlet程序只要跟踪提交form表单的网页的字符集编码即可。只要在处理表单提交的servlet程序中将传递给setCharacterEncoding方法的字符集编码设置为该表单所在页面的字符集编码即可。
(2)
HTTP协议规定浏览器不能向服务器直接传递某些特殊字符(包括中文),必须是这些字符进行URL编码后再传送。
(3)只要超链接、Form表单的action属性设置、请求转发和重定向的URL等任何一种请求路径中要包含参数,就必须对参数部分进行URL编码。对参数进行URL编码时所选择的字符集编码应尽量与当前页面的字符集编码保持一致,也可以用一个参数来指定URL编码内容的字符集编码名称。
jsp中文乱码的根源
java虚拟机中的字符文本的编码采用Unicode编码,而输入/输出设备通常都采用其他的字符集编码(例如,中文系统的键盘输入和显示屏输出都采用GB2312编码),因此java程序在从外设的字节输入流中读取文本和将文本写入到外设的字节输出流时都需要进行字符编码的转换。另外,java程序中的一些字符文本也可能是从java源文件中编译过来的,而java源文件可以采用多种字符集编码来编写,所以,将java源文件编译成java程序时也要进行字符编码转换。
对于jsp来说,还涉及jsp源文件翻译成servlet源文件的过程,而jsp源文件与其翻译成的servlet源文件的字符集编码也可能不同,直接在jsp源文件中编写的字符串在翻译成servlet源文件时也要发生字符编码转换,所以,jsp引擎将jsp页面翻译成servlet源文件时也可能导致中文乱码问题。