现在的位置: 首页 > 综合 > 正文

JAVA编码转换的详细过程理解—>浏览器和服务器的接收和发送数据的编码

2018年02月05日 ⁄ 综合 ⁄ 共 5955字 ⁄ 字号 评论关闭

JAVA编码转换的详细过程理解—>浏览器和服务器的接收和发送数据的编码

一、JAVA编码转换的详细过程

我们常见的JAVA程序包括以下类别:

  *直接在console上运行的类(包括可视化界面的类)

  *JSP代码类(注:JSP是Servlets类的变型)

  *Servelets类

  *EJB类

  *其它不可以直接运行的支持类

这些类文件中,都有可能含有中文字符串,并且我们常用前三类JAVA程序和用户直接交互,用于输出和输入字符,

如:我们在JSP和Servlet中得到客户端送来的字符,这些字符也包括中文字符。

无论这些JAVA类的作用如何,这些JAVA程序的生命周期都是这样的:

  1)*编程人员在一定的操作系统上选择一个合适的编辑软件来实现源程序代码并以.java扩展名保存在操作系统中,

       2)*例如我们在中文win2k中用 记事本编辑一个java源程序;

  3)*编程人员用JDK中的javac.exe来编译这些源代码,形成.class类(JSP文件是由容器调用JDK来编译的);

  4)*直接运行这些类或将这些类布署到WEB容器中去运行,并输出结果。

那么,在这些过程中,JDK和JVM是如何将这些文件如何编码和解码并运行的呢?

这里,我们以中文win2k操作系统为例说明JAVA类是如何来编码和被解码的。

第一步:我们在中文win2k中用编辑软件如记事本编写一个Java源程序文件(包括以上五类JAVA程序),程序文件在保存时默认采用了操作系统默认支持GBK编码格式(操作系统默认支持的格式为 file.encoding格式)形成了一个.java文件。也即是java程序在被编译前,我们的JAVA源程序文件是采用操作系统默认支持的 file.encoding编码格式保存的,java源程序中含有中文信息字符和英文程序代码;要查看系统的file.encoding参数,可以用以下代码:

public class ShowSystemDefaultEncoding {

  public static void main(String[] args) {

      String encoding = System.getProperty("file.encoding");

      System.out.println(encoding);

  }

}

 第二步,我们用JDK的javac.exe文件编译我们的Java源程序,由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的JAVA源程序的编码格式,则javac.exe首先获得我们操作系统默认采用的编码格式,也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数 (它保存的就是操作系统默认的编码格式,如WIN2k,它的值为GBK),然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。然后,javac把转换后的unicode格式的文件进行编译成.class类文件,此时.class文件是UNICODE编码的,它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件。对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.encoding格式转化为UNICODE格式了。这一步中,对于JSP源程序文件是不同的,对于JSP,这个过程是这样的:即WEB容器调用JSP编译器,JSP编译器先查看JSP文件中是否设置有文件编码格式,如果JSP文件中没有设置JSP文件的编码格式(用这句话<%@
page language="java"  pageEncoding="UTF-8">来进行jsp文件的编码格式),则 JSP编译器调用JDK先把JSP文件用JVM默认的字符编码格式(也即WEB容器所在的操作系统的默认的file.encoding)转化为临时的 Servlet类,然后再把它编译成UNICODE格式的class类,并保存在临时文件夹中。如:在中文win2k上,WEB容器就把JSP文件从 GBK编码格式转化为UNICODE格式,然后编译成临时保存的Servlet类,以响应用户的请求。

第三步:运行第二步编译出来的类,分为三种情况:

  A、 直接在console上运行的类

  B、 EJB类和不可以直接运行的支持类(如JavaBean类)

  C、 JSP代码和Servlet类

  D、 JAVA程序和数据库之间 下面我们分这四种情况来看。

A、直接在console上运行的类:

  这种情况,运行该类首先需要JVM支持,即操作系统中必须安装有JRE。运行过程是这样的:首先java启动JVM,此时JVM读出操作系统中保存的class文件并把内容读入内存中,此时内存中为UNICODE格式的class类,然后JVM运行它,如果此时此类需要接收用户输入,则类会默认用file.encoding编码格式对用户输入的串进行编码并转化为unicode保存入内存(用户可以设置输入流的编码格式)。程序运行后,产生的字符串(UNICODE编码的)再回交给JVM,最后JRE把此字符串再转化为file.encoding格式(用户可以设置输出流的编码格式)传递给操作系统显示接口并输出到界面上。以上每一步的转化都需要正确的编码格式转化,才能最终不出现乱码现象。

B、EJB类和不可以直接运行的支持类(如JavaBean类):

  由于EJB类和不可以直接运行的支持类,它们一般不与用户直接交互输入和输出,它们常常与其它的类进行交互输入和输出,所以它们在第二步被编译后,就形成了内容是UNICODE编码的类保存在操作系统中了,以后只要它与其它的类之间的交互在参数传递过程中没有丢失,则它就会正确的运行。

C、 JSP代码和Servlet类:

  经过第二步后,JSP文件也被转化为Servlets类文件,只不过它不像标准的Servlets一校存在于classes目录中,它存在于WEB容器的临时目录中,故这一步中我们也把它做为Servlets来看。

  对于Servlets,客户端请求它时,WEB容器调用它的JVM来运行Servlet,首先,JVM把Servlet的class类从系统中读出并装入内存中,内存中是以UNICODE编码的Servlet类的代码,然后JVM在内存中运行该Servlet类,如果Servlet在运行的过程中,需要接受从客户端传来的字符如:表单输入的值和URL中传入的值,此时如果程序中没有设定接受参数时采用的编码格式,则WEB容器会默认采用ISO- 8859-1编码格式来接受传入的值并在JVM中转化为UNICODE格式的保存在WEB容器的内存中。Servlet运行后生成输出,输出的字符串是
UNICODE格式的,紧接着,容器将Servlet运行产生的UNICODE格式的串(如html语法,用户输出的串等)直接发送到客户端浏览器上并输出给用户,如果此时指定了发送时输出的编码格式,则按指定的编码格式输出到浏览器上,如果没有指定,则默认按ISO-8859-1编码发送到客户的浏览器上。

D、Java程序和数据库之间:

  对于几乎所有数据库的JDBC驱动程序,默认的在JAVA程序和数据库之间传递数据都是以ISO-8859-1为默认编码格式的,所以,我们的程序在向数据库内存储包含中文的数据时,JDBC首先是把程序内部的UNICODE编码格式的数据转化为ISO-8859-1的格式,然后传递到数据库中,在数据库保存数据时,它默认即以ISO-8859-1保存,所以,这是为什么我们常常在数据库中读出的中文数据是乱码。

二、浏览器与服务器交互编码过程

1.发送请求

使用浏览器发送HTTP请求有多种方式:

在浏览器地址栏中直接输入URL;

在页面中通过点击“提交”按钮提交表单;

用户在页面中点击超链接产生的请求;

使用JavaScript脚本的XMLHTTPRequest对象发送请求。

(1)在浏览器地址栏中直接输入URL

     路径和浏览器的发送URL设置的编码有关系,查询字符串参数用系统默认编码进行编码。

(2)在页面中通过单击“提交”按钮来提交表单

    路径和浏览器的发送URL设置的编码有关系,查询字符串参数用网页的编码进行编码。

(3)在页面中单击超链接产生的请求

    路径和浏览器的发送URL设置的编码有关系,查询字符串参数用网页的编码进行编码。

(4)使用XMLHTTPRequest对象发送请求

最后,我们来看一下使用JavaScript脚本来发送请求的情形。XMLHTTPRequest对象(下面简称XHR)是构成Ajax应用程序的基础,它允许JavaScript脚本直接向服务器发送HTTP请求,在页面不刷新的前提下与服务器通信,提交和获取数据。

使用XHR对象发送请求也分为Get和Post两种。

IE中使用XHR对象发送“Get”请求时,对URL所使用的编码规则和在地址栏中输入URL是一致的。

Firefox中使用XHR对象发送“Get”请求时始终使用UTF-8编码对URL进行转义。

发送“Post”请求时,参数和URL分离,参数部分在消息体中,使用UTF-8编码。

要使Web服务器能够正确识别,最好在Content-type消息头中添加“Charset”信息,如以下代码段 所示:

//创建XHR 对象,并准备URL 和请求参数

xmlHttp.open("Post",url,true);

xmlHttp.setRequestHeader("Content-type", 

       "application/x-www-form-urlencoded;charset=UTF-8");

xmlHttp.setRequestHeader("Content-length", params.length);

xmlHttp.setRequestHeader("Connection", "close");

xmlHttp.send(params);

请注意,设置上述请求的消息头只能用来告知服务器该消息体所使用的编码,并不能通过修改此消息头的值来改变该请求所使用的编码。

2.接受响应

前文描述了浏览器在发送HTTP请求时选取编码的行为。那么从服务器端返回HTTP响应时,浏览器又是如何判断该响应使用了何种编码的呢?

浏览器判断返回的HTTP响应消息所使用的编码遵循以下一系列规则。

首先,浏览器会检查HTTP响应中的“Content-type”消息头。如“text/html; charset=UTF-8”,表明该消息所包含的内容是纯文本的HTML文档,采用UTF-8编码。但在很多情况下,服务器返回的Content- type消息头并不包含“charset”信息。

当响应消息不包含“charset”信息时,浏览器会尝试自动探测编码。第一个步骤是检查响应消息体的开头是否包含UTF-8的BOM(字节顺序标 记,Byte Order Marker)。BOM是一种用来判断文件编码的特定字节标记,如果一个文件的开头几个字节包含了UTF-8的BOM,那么浏览器就可以断定这个HTML 文件是采用UTF-8编码的。

如果该HTML中不包含BOM,那么,浏览器就会尝试寻找HTML页面中的<meta>标记,如:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

如果页面中又不包含<meta>标记,那么,浏览器将采用默认的编码来解析。在中文的IE和Firefox里就是采用GBK或GB2312编码。

因此,要使服务器端返回的响应消息能够正确地被浏览器解析,最简单有效的方法就是在响应的“Content-type”消息头中设置charset属性。在Servlet编程中可以在doGet()或doPost()方法中调用:

response.setCharacterEncoding("UTF-8")

在JSP编程中可以在页面开头指定响应的编码:

<%@ page language="java" contentType="text/html; charset=UTF-8" import="java. util.*"

   pageEncoding="UTF-8"%>

三、JSP与Servlet中的编码说明

pageEncoding="UTF-8" 设置jsp编译成.java文件的编码

contentType="text/html; charset=UTF-8":设置页面编码,告诉浏览器以什么编码来解析文档,以什么编码来发送数据(当请求为get,post);

request.setCharacterEncoding("UTF-8");设置web服务器对浏览器发送的请求数据的编码(默认是IS08859-1);

response.setCharacterEncoding("UTF-8");设置web服务器给浏览器发送的回复数据的编码(默认是IS08859-1);

浏览器和服务器的接收和发送数据的编码 

1 、浏览器时如何对接收和发送数据的编码?

1)浏览器在发送数据时候分3种:一是浏览器直接用URL提交的数据,另外两种是用表单的GET和POST方式提交的数据。

     URL:如果是javascript产生的URL和超链接则转换为get提交,其它的则以浏览器的编码为准。

    GET和POST根据页面编码来发送数据。

2)response.setCharacterEncoding("UTF-8")的作用是指定对服务器的响应进行重新编码(默认是IS08859-1)。

同时,浏览器也是根据这个参数来对其接收的数据进行重新编码(解码),

浏览器解码顺序response.setCharacterEncoding——contentType——pageEncoding。

2 、服务器是如何接收和发送数据的编码

1)对于发送数据,服务器采用response.setCharacterEncoding—contentType—pageEncoding的优先顺序,对要发送的数据进行编码。

    浏览器根据这个编码进行解析,显示给浏览器。

2)对于接收数据:

request.setCharacterEncoding("UTF-8");设置web服务器对浏览器发送的请求数据的编码(默认是以IS08859-1编码格式去接受数据);

抱歉!评论已关闭.