PS:本人是用的win10系统 本地默认的编码是 GBK 我记得好像 XP 是GB2312, win 7和win8 都是GBK (我们可以通System.getProperty("file.endcoding")来获取本地编码)
为了演示的方便我是直接在Servlet 中的doGet()方法中向浏览器中发送数据
A:用字节输出流发送数据
利用字节输出流向浏览器中发送 中国两个字
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //获取字节输出流对象
- OutputStream out=response.getOutputStream();
- //向浏览器发送数据
- out.write("中国".getBytes());
- }
复制代码 然后发布web应用 启动Tomcat 在浏览器中访问上面doGet()方法所在的servlet 在浏览器中可以看到中国两个字 没有乱码的问题
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //获取字节输出流对象
- OutputStream out=response.getOutputStream();
- //向浏览器发送数据
- out.write("中国".getBytes("UTF-8"));
-
- }
复制代码 然后发布web应用 启动Tomcat 在浏览器中访问上面doGet()方法所在的servlet 在浏览器中可以看到涓 浗 两个字 产生了乱码问题
为什么第一段代码没有乱码 第二段代码就有乱码问题
首先我们要明确的是 字节输出流 的目的地并不是浏览器 而是 response对象也就是说,字节输出流没有直接将数据写入到浏览器中而是 将数据写入到response对象中,并且response中内置的默认编码是拉丁码表(ISO8859-1);
分析第一段代码:
用字节输出流直接将数据写入到response对象,并且response中内置的默认编码是拉丁码表,这个码表是单字节码表,out.write("中国".getBytes());这句代码是将中国两个字按照本地默认的编码编码成字节数组,字节数组到了response对象,response对象拿每个字节数据查询ISO8859-1得到 ISO8859-1码表中的相对应的字符,然后response对象拿着查询得到的所有字符 再查询 ISO8859-1码表 形成二进制数据 ,再将二进制数据发送到浏览器端。 总的来说 中国两个字在服务器端的二进制数据到了 浏览器端对应的二进制数据 是没有改变,然后浏览器拿着服务器发送过来的二进制数据用系统默认的编码表来解析 所以没有乱码问题;
分析第二段代码:
out.write("中国".getBytes("UTF-8"));这行代码表示将数据按照UTF-8码表进行编码形成二进制数据 ,二进制数据到了response中 ,查询ISO8859-1 ,接着
将二进制数据发送到了浏览器端 ,而浏览器中是按照默认的编码来解析(GBK) 所以乱码;
解决方案:
要是我们保证数据编码和解码使用的码表一致 就可以了 ,这就需要我们告诉浏览器按照我们指定的编码来解码数据 ,所以我们可以使用HTTP响应头来实现这个目的
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //发送响应头告诉浏览器要使用UTF-8编码来解析数据
- response.setHeader("content-type", "text/html;charset=utf-8");
-
- //获取字节输出流对象
- OutputStream out=response.getOutputStream();
-
-
- //向浏览器发送数据
- out.write("中国".getBytes("UTF-8"));
-
- }
复制代码 然后发布web应用 启动Tomcat 在浏览器中访问上面doGet()方法所在的servlet 在浏览器中可以看到中国两个字 不会有乱码问题
总结:用字符流发送数据就要保证编码和解码使用的码表一样 就会不会乱码
PS:其实我们也可用<meta >标签来模拟一个http响应
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //获取字节输出流对象
- OutputStream out=response.getOutputStream();
-
- //发送meta标签
- out.write("<meta http-equiv='content-type' content='text/html;charset=utf-8'>".getBytes());
- //向浏览器发送数据
- out.write("中国".getBytes("UTF-8"));
- }
复制代码 不会乱码
B:用字符打印流向浏览器发送数据
用字符打印流向浏览器中发送 中国两个字
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //获取字符打印流对象
- PrintWriter out=response.getWriter();
- //向浏览器发送数据
- out.write("中国");
- }
复制代码 然后发布web应用 启动Tomcat 在浏览器中访问上面doGet()方法所在的servlet 在浏览器中可以看到两个问号 产生了乱码
分析原因:
用字符打印流直接将数据写入到response对象,由于是字符打印流,数据我们保持原样写入到目的地中,所以中国两个字就直接到了response对象,然后response对象拿着中国两个字去查寻ISO8859-1 ,因为ISO8859-1是拉丁码表里面没有中文,所以是找不到,找不到就会返回未知区域字符(就是问号),接着response对象是把两个问号的二进制数据写到浏览器中,浏览器中拿到的二进制数据实际上是两个问号的二进制数据,浏览器再解析二进制数据,所以看到的是两个问号 ;总的来说 中国两个字在服务器端的二进制数据到了 浏览器端对应的二进制数据 就发生了变化;
解决方法:
产生上面问题的根本原因 就是 要被发送的数据在浏览器端对应的对应二进制数据 到了 浏览器端接受到的二进制数据发生了变化,出现这个问题就是由于数据在传送的途中查询了SO8859-1导致的,只要我们修改了response中的码表就可以了,这需要通过response对象的setCharacterEncoding()方法来是实现
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //修改response中的编码
- response.setCharacterEncoding("GBK");
-
- //获取字符打印流对象
- PrintWriter out=response.getWriter();
- //向浏览器发送数据
- out.write("中国");
- }
复制代码 然后发布web应用 启动Tomcat 在浏览器中访问上面doGet()方法所在的servlet 在浏览器中可以看中国两个字 没有乱码
细节问题:基于上面的代码而言 要是我们为response指定编码的时候 指定的是UTF-8 代码如下:
- public class ItcastBlogServletCharSet extends HttpServlet {
-
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //修改response中的编码
- response.setCharacterEncoding("utf-8");
-
- //获取字符打印流对象
- PrintWriter out=response.getWriter();
- //向浏览器发送数据
- out.write("中国");
- }
复制代码
然后发布web应用 启动Tomcat 在浏览器中访问上面doGet()方法所在的servlet 在浏览器中可以看涓 浗 两个字 乱码了
原因就是浏览器是用的默认的编码(GBK)来解析数据的,应该使用UTF-8 所以要用http响应指定浏览器用utf-8编码来解析
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //修改response中的编码
- response.setCharacterEncoding("utf-8");
-
- //用http响应指定浏览器用utf-8编码来解析
- response.setHeader("content-type", "text/html;charset=utf-8");
- //获取字符打印流对象
- PrintWriter out=response.getWriter();
- //向浏览器发送数据
- out.write("中国");
- }
复制代码 这样修改了就不会乱码了
|
|