`
bjrobin
  • 浏览: 13625 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

尚学堂.张志宇.乱码分析_02_servlet乱码.doc

    博客分类:
  • java
阅读更多
1 重要结论
J2SE 5.0 用的是Unicode 4.0
J2SE 6.0 用的也是Unicode 4.0
Java编程语言用16位的编码代表文本。使用UTF-16编码.
一个 char 表示一个 UTF-16 编码单元
并不是一个char代表一个字符,因为一个增补字符需要2个char来代表

2 准备知识:
2.1 gbk编码
字符“我”的gbk编码: ced2
可以到GBK编码表去验证
http://www.microsoft.com/globaldev/reference/dbcs/936.mspx
2.2 utf16编码
字符“我”的utf-16编码:编码,6211
可以参考从unicode官方网站上下载下来的《U4E00.pdf》确认此事。
其实U4E00.pdf里面查到的只是代码点。
而utf-16编码,对于普通字符来说(即不是增补字符),和代码点是一致的。
2.3 utf-8编码
字符“我”的utf-8编码: e6 88 91
可以靠下面代码来验证:
import java.io.UnsupportedEncodingException;

public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "我";
byte[] bytes = s.getBytes("utf-8");
for (int i = 0; i < bytes.length; i++) {
System.out.println(Integer.toHexString(bytes[i]));
}
}
}

3 场景1
response.setContentType("text/html;charset=GBK"); 没写
request.setCharacterEncoding("GBK"); 没写
server.xmlConnectorURIEncoding="GBK" 没设置

OneParam.java
import javax.servlet.*;
import javax.servlet.http.*;

import java.io.*;

public class OneParam extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String s = "我";
System.out.println(s);
out.println(s);
}
}



web.xml
    <servlet>
        <servlet-name>OneParam</servlet-name>
        <servlet-class>OneParam</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>OneParam</servlet-name>
        <url-pattern>/servlet/OneParam</url-pattern>
    </servlet-mapping>

访问这个地址:http://127.0.0.1/my/servlet/OneParam
观察到的现象是:页面本身有乱码。

首先,编译得到的字节码文件中,这个字符被存储为utf-8编码形式。
可以用ultraedit软件,打开class文件,切换到16进制来验证。

当执行这句话时候,
String s = "我";
先说=右边,要在方法区创建一个字符串对象出来。
jvm在读入字节码的时候,当然知道这个字符串在字节码中是默认存成utf-8编码的。
unicode代码点和uft-8编码之间的对应关系是固定的。即:
UCS-2 (UCS-4) 位序列 第一字节 第二字节 第三字节 第四字节
U+0000 .. U+007F 00000000-0xxxxxxx 0xxxxxxx
U+0080 .. U+07FF 00000xxx-xxyyyyyy 110xxxxx 10yyyyyy
U+0800 .. U+FFFF xxxxyyyy-yyzzzzzz 1110xxxx 10yyyyyy 10zzzzzz
U+10000..U+1FFFFF 00000000-000wwwxx-
xxxxyyyy-yyzzzzzzz 11110www 10xxxxxx 10yyyyyy 10zzzzzz
通过固定的转换关系,jvm能够得到正确的unicode代码点(6211)。
对于普通字符,unicode代码点和utf-16编码是一致的。(增补字符除外)
即会在内存里面表示为6211。
局部变量s指向了这个对象。
s62 11。
由于内存里面记录了“我”这个字符的正确的uft-16编码。
当然我们执行下面这句话能够得到正确的中文。
System.out.println(s);

接下来是:
out.println(s);
把这个字符串传到客户端浏览器。JVM这里可不是把内存里面的内容不做任何转换直接传到浏览器。JVM必须以某种编码形式来传递这个字符串。因为没有指明到底以什么编码来传递。所以默认是iso8859-1。
所以tomcat帮忙调用s.getBytes("iso8859-1"),
因为在iso8859-1编码表里面,没有“我”这个字符。我们会得到错误的iso8859-1编码。
这会得到1个字节,如果用10进制标识为63,如果用16进制标识为3f,tomcat然后把这1个字节传给客户端。

下面代码演示s.getBytes("iso8859-1")会得到错误的编码:
import java.io.UnsupportedEncodingException;

public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "我";
byte[] bytes = s.getBytes("iso8859-1");
for (int i = 0; i < bytes.length; i++) {
System.out.println(Integer.toHexString(bytes[i]));
//System.out.println(bytes[i]);
}
}
}



客户端只接收到这个3f,我们可以靠下面的程序验证这一点:
TestHTTP.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;

import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TestHTTP {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.0.1", 80);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s
.getOutputStream()));
bw.write("GET /my/servlet/OneParam HTTP/1.1");
bw.newLine();
bw.write("Host: 127.0.0.1:80");
bw.newLine();
bw.write("Content-Type: text/html");
bw.newLine();
bw.newLine();
bw.flush();
// BufferedReader br = new BufferedReader(new InputStreamReader(s
// .getInputStream()));
// String str = null;
// while ((str = br.readLine()) != null) {
// System.out.println(str);
// }
InputStream br = s.getInputStream();
int i = 0;
while ((i = br.read()) != -1) {
System.out.print(" " + i);
}
bw.close();
br.close();
s.close();
}

}


72 84 84 80 47 49 46 49 32 50 48 48 32 79 75 13 10 83 101 114 118 101 114 58 32 65 112 97 99 104 101 45 67 111 121 111 116 101 47 49 46 49 13 10 67 111 110 116 101 110 116 45 76 101 110 103 116 104 58 32 51 13 10 68 97 116 101 58 32 84 104 117 44 32 50 51 32 65 112 114 32 50 48 48 57 32 48 49 58 49 55 58 49 52 32 71 77 84 13 10 13 10 63 13 10
看到没?倒数第3个字节是63。如果用16进制标识为3f

ascii字符集里规定,3f是“?”这个字符
可以到这个地址来验证:http://www.jimprice.com/jim-asc.shtml
你的浏览器菜单,察看编码这一项,可能自动设置为gb2312.即使这样。浏览器依然会按照gbk来显示内容。
gbk编码表,和ascii编码是兼容的。所以会显示成1个?
可以到这里来验证。
http://msdn.microsoft.com/zh-cn/goglobal/cc305153(en-us).aspx

即使你通过浏览器菜单察看编码这一项设置为其它的编码。比如:iso8859-1
看到的也是?,因为iso8859-1和ascii编码也是兼容的。

4 附
gbk编码

0
2
分享到:
评论
1 楼 因为青所以涩 2012-01-30  
楼主厉害,从本质上分析了乱码产生的原因

相关推荐

    hadoop大数据培训零基础学习hadoop-北京尚学堂.docx

    hadoop大数据培训零基础学习hadoop-北京尚学堂.docxhadoop大数据培训零基础学习hadoop-北京尚学堂.docx

    尚学堂_Sping_0200_IOC_Introduction

    【标题】:尚学堂_Spring_0200_IOC_Introduction 【内容详解】: Spring 框架是 Java 应用开发中的一个重要组件,它以其依赖注入(Dependency Injection,简称 DI)和控制反转(Inversion of Control,简称 IOC)...

    尚学堂_Spring_0700_IOC_Collections

    总之,"Spring_0700_IOC_Collections"涵盖了Spring框架中关于IoC容器处理集合依赖的重要知识,包括XML配置、Java配置、注解注入以及源码分析等多个方面。通过学习这部分内容,开发者可以更深入地理解Spring的IoC机制...

    尚学堂_Spring_0300_IOC_Injection_Type

    标题中的"Spring_0300_IOC_Injection_Type"指的是Spring框架中的依赖注入(Dependency Injection,简称DI)机制,特别是关于类型注入(Type Injection)的知识点。在Spring框架中,依赖注入是核心特性之一,它使得...

    百战程序员答案javase基础部分

    JavaSE(Java Standard Edition)是Java编程语言的基础部分,涵盖了从基本语法到核心特性的一系列知识。本资料集“百战程序员答案javase基础部分”是针对Java初学者和进阶者的宝贵资源,包含了从第一章到第十章的...

    尚学堂_Spring_0800_IOC_Auto_Wire

    标题中的"Spring_0800_IOC_Auto_Wire"指的是Spring框架中的依赖注入(Dependency Injection,简称DI)特性,特别是自动装配(Auto Wiring)。在Spring框架中,IOC(Inversion of Control,控制反转)是一种设计模式...

    尚学堂_Spring_0600_IOC_Bean_Scope

    标题中的“Spring_0600_IOC_Bean_Scope”涉及到的是Spring框架中的核心概念——控制反转(Inversion of Control, 简称IOC)以及Bean的作用域(Scope)。在这个主题下,我们将深入探讨Spring如何通过IOC管理Bean的...

    hadoop大数据培训零基础学习hadoop-北京尚学堂.pdf

    最后,建议配合尚学堂的肖斌Hadoop经典视频教程以及云计算极限班的课程进行系统学习,这些资源将提供详细的指导和实例,帮助你逐步深入理解和掌握Hadoop大数据技术。同时,持续实践和参与社区讨论也是提升技能的重要...

    SERVLET_JSP.01.ppt

    尚学堂servlet_jsp视频教程中使用的ppt课件,SERVLET_JSP.01.ppt

    Java设计模式

    2. 尚学堂_设计模式_责任链_02.avi:接着,可能会讲解如何在实际代码中应用责任链,可能包括如何实例化处理器对象,以及如何设置和传递请求。 3. 尚学堂_设计模式_责任链_03.avi:随着课程的深入,可能讨论到如何...

    java学习顺序.doc

    尚学堂科技提供了相关的视频教程,如"张志宇_SERVLET_JSP_视频教程",还有JDBC、MySQL和Tomcat的使用,这些是构建Web应用的基础。通过"JAVA_网上商城项目视频讲解"这样的实战教程,可以提高实际操作能力。 深入J2EE...

    尚学堂_Spring_0100_模拟Spring

    《尚学堂_Spring_0100_模拟Spring》 在深入探讨Spring框架之前,我们需要先理解Spring的核心理念。Spring是一个开源的Java平台,它主要为构建企业级应用提供了全面的编程和配置模型。它的核心特性是依赖注入...

    Lucene_ShangXueTang.rar_文章/文档_Java_

    《尚学堂全文检索系统——深入理解Lucene》 在IT领域,搜索引擎技术是不可或缺的一部分,尤其是在大数据时代,如何高效地从海量信息中快速找到所需内容成为了一项挑战。Java平台上的Lucene,作为一款强大的开源全文...

    JAVA视频学习顺序

    - **尚学堂科技_张志宇_SERVLET_JSP_视频教程_第一版**:介绍了Servlet和JSP的基础知识,这是构建动态网页的基础。 - **尚学堂科技_马士兵_JAVA_系列视频教程_BBS_2007**:通过实际案例,让学员了解如何运用所学知识...

    hibernate资料3

    接着,"008_尚学堂马士兵_Java视频教程_Hibernate3.3.2_常见OR框架简介.avi"中,马士兵老师会对比分析其他的ORM框架,如iBatis等,帮助你了解它们与Hibernate的区别和联系,进一步巩固对Hibernate的理解。...

    尚学堂Java笔记.pdf

    尚学堂Java笔记.pdf 本资源主要讲述Java语言的基础知识和应用,包括J2SDK、JRE、JDK、classpath、path、Java应用程序、递归调用等内容。 一、J2SDK和JRE Java2 Software Development Kit(J2SDK)是Java开发需要...

    441769547180350是男人就撑20秒【尚学堂】.zip

    441769547180350是男人就撑20秒【尚学堂】.zip

    全网最新尚学堂hadoop大数据视频教程.doc

    1. **数据分析**:通过对大量数据的分析,帮助企业做出更明智的决策。 2. **搜索引擎**:Hadoop可以用来索引和搜索互联网上的大量网页数据。 3. **推荐系统**:通过分析用户的浏览历史和购买记录,向用户推荐可能感...

    我的ServletJSP课件

    首先,"servletConfig.doc"可能涉及到Servlet配置的相关内容。在Servlet中,我们通常通过`web.xml`文件来配置Servlet,比如定义Servlet类、映射URL路径、设置初始化参数等。这文档可能详细解释了如何编写和理解`web....

Global site tag (gtag.js) - Google Analytics