论坛首页 Java企业应用论坛

浅析Java web程序之客户端和服务器端交互原理

浏览 17454 次
精华帖 (0) :: 良好帖 (12) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-09-16   最后修改:2009-09-18
1. 协议

a. TCP/IP整体构架概述

   TCP/IP协议并不完全符合OSI的七层参考模型。传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。该模型的目的是使各种硬件在相同的层次上相互通信。这7层是:物理层、数据链路层、网路层、传输层、话路层、表示层和应用层。而TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为:

   i.   应用层:应用程序间沟通的层,如超文本传送协议(HTTP)、简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。

   ii.  传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
  
   iii. 互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。

   iv.  网络接口层:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。

b. HTTP协议介绍:

   i.   HTTP是一种超文本传送协议(HyperText Transfer Protocol),是一套计算机在网络中通信的一种规则。在TCP/IP体系结构中,HTTP属于应用层协议,位于TCP/IP协议的顶层

   ii.  HTTP是一种无状态的的协议,意思是指 在Web 浏览器(客户端)和 Web 服务器之间不需要建立持久的连接。整个过程就是当一个客户端向服务器端发送一个请求(request),然后Web服务器返回一个响应 (response),之后连接就关闭了,在服务端此时是没有保留连接的信息。

   iii. HTTP 遵循 请求/响应(request/response) 模型的,所有的通信交互都被构造在一套请求和响应模型中。

   iv.  浏览WEB时,浏览器通过HTTP协议与WEB服务器交换信息,Web服务器向Web浏览器返回的文件都有与之相关的类型,这些信息类型的格式由MIME定义。

c. 协议的java实现方式
  
   不论是TCP/IP协议也好,还是HTTP协议也好,java都是通过套接字(java.net.Socket)来实现的,可以参考我的另一篇技术博客:一个项目看java TCP/IP Socket编程(1.3版)


2. HTTP报文接口及客户端和服务器端交互原理

a. HTTP定义的事务处理由以下四步组成:

   i.  建立连接:

   例如我在浏览器里输入 http://cuishen.iteye.com,客户端请求这个地址时即打开了web服务器HTTP端口的一个套接字。因为在网络中间作为传递数据的实体介质就是网线,数据实质上是通过IO流进行输出和输入,这就不难理解我们为什么在写一个Servlet的时候要引用 import java.io.*; 的原因 ,包括我们在向客户端回发结果的时候要用到PrintWriter对象的println()方法。其实请求的这个地址还要加上端口号80,80可以不写,是因为浏览器默认的端口号是80。

   在Java底层代码中是这样实现的,只不过它们已经帮我们做了。
Socket socket = new Socket("cuishen.iteye.com",80);
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();


   ii. 客户端发送HTTP请求报文(request)

   一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令,是一个ASCII文本请求行,后跟0个或多个HTTP头标,一个空行和实现请求的任意数据。

   即报文分四个部分:请求行,请求头标,空行和请求数据

     1)请求行
    
     请求行由三个标记组成:请求方法、请求URL和HTTP版本,中间用空格分开

     例如: GET cuishen.iteye.com/blog/242842 HTTP/1.1

HTTP规范定义了8种可能的请求方法:(最常见的就是 GET 和 POST 两种方法)

GET -- 检索URI中标识资源的一个简单请求
HEAD -- 与GET方法相同,服务器只返回状态行和头标,并不返回请求文档
POST -- 服务器接受被写入客户端输出流中的数据的请求
PUT -- 服务器保存请求数据作为指定URI新内容的请求
DELETE -- 服务器删除URI中命名的资源的请求
OPTIONS -- 关于服务器支持的请求方法信息的请求
TRACE -- Web服务器反馈Http请求和其头标的请求
CONNECT -- 已文档化但当前未实现的一个方法,预留做隧道处理

     2)请求头标

请求头标:由key :value 健值组成,每行一对。请求头标用来通知服务器有关客户端的功能和标识。

HOST -- 请求的哪一个服务器端地址,主地址,比如:我的技术blog:cuishen.iteye.com
User-Agent -- 用户即客户端可以使用的浏览器 ,如: Mozilla/4.0
Accept -- 即客户端可以接受的MIME 类型列表,如image/gif、text/html、application/msword
Content-Length -- 只适用于POST请求,以字节给出POST数据的尺寸

     3)空行 

发送回车符和退行,通知服务器以下不再有头标。

     4)请求数据

使用POST传送数据,最常使用的是Content-Type和Content-Length头标。

    
     请求报文总结:
    
     我们可以这样写出一个标准的 HTTP请求:

POST  /blog/242842 HTTP1.1
HOST: cuishen.iteye.com/
User-Agent: Mozilla/4.0
Accpt: image/gif,text/html,application/pdf,image/png...
key=value&key=value&key=value...... (POST()请求的数据)

     这上面的一个例子意思是:
    
我要去访问的服务器端的地址是cuishen.iteye.com/ 它下面的资源 /blog/242842
连起来就是: cuishen.iteye.com/blog/242842
这个页面用的是 HTTP1.1 规范,我的浏览器版本是Mozilla/4.0 
可以支持的MIME格式为  image/gif,text/html,application/pdf,image/png...等等

这个MIME格式我们在servlet中写法是:response.setContentType("text/html;charset=gb2312");
或者在jsp中写法是:<%@ page contentType="text/html;charset=gb2312"%>
或者在html中写法是:<meta http-equiv="content-Type" content="text/html; charset=gb2312">

GET 和 POST 最直观的区别就是:GET方法将数据的请求跟在了所请求的URL后面,也就是在请求行里面我们是这么样来做的:

GET  /blog/242842?key=value&key=value&key=value......HTTP1.1

实际上用 GET 是这样传递数据的:

http://cuishen.iteye.com/?page=2......


   iii.服务器端响应请求生成结果并回发(response)


     Web 服务器解析请求,定位指定的资源 http://cuishen.iteye.com/blog/242842


     1)根据请求时的 GET/POST 对应的用servlet里的 doGet() / doPost()方法来处理(有可能是一些业务逻辑,也有可能是一些验证等等,也有可能是一些数据查询,提交等等)其有效的数据就来源于key=value&key=value&key=value......,以及其它的一些封装在 request 对象中的数据资源。

    
     2)处理请求之后,由 response 对象得到 java.io.PrintWriter 输出流对象out,通过 out.println(); 将数据以指定的格式,如按照response.setcontentType("text/html;charset=gb2312");的格式输出到输出流。

     它的响应报文与请求报文非常类似,其区别就在于:我们在请求阶段的请求行被状态行给替换了,再来看响应报文:


     3)一个响应报文由四个部分组成:状态行、响应头标、空行、响应数据:

(a).状态行:

    状态行由三个标记组成:HTTP版本、响应代码和响应描述。
                                                               
HTTP1.1 --- 100 --- continue  //继续追加后继内容
HTTP1.1 --- 200 --- OK  //一切正常
HTTP1.1 --- 301 --- Moved Permanently  //请求的文档在其它地方,会自动连接
HTTP1.1 --- 403 --- Forbidden  //绝对拒绝你访问这个资源,不管授权没有
HTTP1.1 --- 400 --- Bad Request  //客户端请求中的不良语法
HTTP1.1 --- 404 --- Not Found  //最常见,绝对是大名鼎鼎的找不到

    HTTP响应码:

1xx:提示性信息,告诉客户端应该对某些其它的动作作出响应
2xx:这些就代表了请求成功
3xx:重定向,为了完成请求,必须进一步执行的动作
4xx:客户端错误
500-599: 服务器端的错误

(b).响应头标:像请求头标一样,它们指出服务器的功能,标识出响应数据的细节。

    Date: Sat, 31 Dec 2005 23:59:59 GMT  --响应生成的日期和时间
    ContentType: 'text/html;charset=gb2312'
            Content-Length: 122  --响应中的字节数,只在浏览器使用永久(Keep-alive)HTTP连接时需要。

(c).空行:最后一个响应头标之后是一个空行,发送回车符和退行,表明服务器以下不再有头标。

(d).响应数据:HTML文档和图像等,也就是HTML本身。out.println("<html>......");写到客户端。
<html>
<head>
<title>Welcome to cuishen's IT blog</title>
</head>
<body>
<!-- 这里是具体的内容,看到了这里
相信大家对 HTTP 工作原理及客户端与服务器交互过程已经很清楚了吧
--> 
</body>
</html>


   iv. 服务器端关闭连接,客户端解析回发响应报文,恢复页面

1)浏览器先解析状态行,查看请求是否成功的状态代码--HTTP响应码:404 400 200 ....

2)解析每一个响应头标,如:

ContentType: text/html;charset=gb2312                                                                                                                                                 
Content-Length: 122 --- 响应中的字节数,只在浏览器使用永久(Keep-alive)HTTP连接时需要。

3)读取响应数据HTML,根据标签<html></html>中的内容恢复标准的HTML格式页面或者其它。

4)一个HTML 文档可能包含其它的需要被载入的资源,浏览器会识别,并对这些资源再进行额外的请求,这个过程可以是循环的方式一直到所有的数据都按照响应头标中规定的格式恢复到页面中。

5)数据传送完毕,服务器端关闭连接,即无状态协议。

3. 总结

不要被高深的名词和理论吓到,其实HTTP客户端和服务器端的交互原理很简单:即先是浏览器和服务器端建立Socket无状态连接,也就是短连接,然后通过IO流进行报文信息(这个报文是严格遵循HTTP报文接口的)的交互,最后会话结束后就关闭连接。对于这些底层的协议和报文的打包解包交互的实现,其实java和浏览器早都已经封装好了,程序员只要专注于业务逻辑的实现就行啦,这些都不必关心!!

   发表时间:2009-09-17  
引用

本质上formBean是被翻译成字节流然后写到客户端的,只要是把对象的属性保存成字节流(String也是)就是序列化,把对象持久化就是序列化的过程

如果我们使用Servlet+JavaBean的时候。我们不需要序列化,因为我们直接在服务端把对象转换为字符串了。如果我们使用Struts的时候,我们把序列化后的对象传输给客户端,客户端是没有jre环境的,那如何反序列化对象呐?
0 请登录后投票
   发表时间:2009-09-17  
lookdd1 写道
引用

本质上formBean是被翻译成字节流然后写到客户端的,只要是把对象的属性保存成字节流(String也是)就是序列化,把对象持久化就是序列化的过程

如果我们使用Servlet+JavaBean的时候。我们不需要序列化,因为我们直接在服务端把对象转换为字符串了。如果我们使用Struts的时候,我们把序列化后的对象传输给客户端,客户端是没有jre环境的,那如何反序列化对象呐?


同问。。
个人理解(没有经过验证),javaBean 只是方便我们在jsp上取数据,和在struts 中 对传输的数据进行注入到formbean 中。javaBean 如果要序列化的话是因为:“Bean的状态信息通常是在设计时配置的。这些状态信息必须保存起来,供程序启动的时候用;对象序列化就负责这个工作。---引用http://dodomail.iteye.com/blog/107344 的句子”

在客户端应该是进行不了反序列化的,因为客户端对服务器端应该是透明的。
0 请登录后投票
   发表时间:2009-09-17  
lookdd1 写道
引用

本质上formBean是被翻译成字节流然后写到客户端的,只要是把对象的属性保存成字节流(String也是)就是序列化,把对象持久化就是序列化的过程

如果我们使用Servlet+JavaBean的时候。我们不需要序列化,因为我们直接在服务端把对象转换为字符串了。如果我们使用Struts的时候,我们把序列化后的对象传输给客户端,客户端是没有jre环境的,那如何反序列化对象呐?

对这个问题小菜我谈一下我的观点,首先,首先Struts的控制器通过截获请求,得到请求参数实例化formbean,要给客户返回一个页面是Action作的,如果页面要得到数据,那么肯定要从web作用域中去取得对象中的信息是吧?我认为这个绝对不需要反序列化的,因为web作用域是由web容器去维护的,那么在JSP处理处理返回页面的时候,当遇到页面中的标签属性,或者el表达式时,回去服务器的web作用域去匹配相对应的值,最后将处理完成的数据封装到响应对象中返回给客户端。
小菜经验尚浅那里说的不对不好请大家指正。
0 请登录后投票
   发表时间:2009-09-17  
看了很久没弄明白,http交互原理和struts 有什么关系。
0 请登录后投票
   发表时间:2009-09-17   最后修改:2009-09-18
yyjn12 写道
看了很久没弄明白,http交互原理和struts 有什么关系。


对于网友的疑问,我特地查了官方API文档:

以下是我从struts1.3.8官方API文档里找到的

引用
Because ActionForms are JavaBeans, subclasses should also implement Serializable, as required by the JavaBean specification. Some containers require that an object meet all JavaBean requirements in order to use the introspection API upon which ActionForms rely.


翻译过来是说:因为ActionForms 是 JavaBeans,所以它的子类都要实现Serializable接口,这是JavaBean规范定义的,一些容器要求一个对象要满足所有的JavaBean规范以便能使用ActionForms所依赖的内省API。

内省是 Java 语言对 Bean 类属性、事件的一种缺省处理方法。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚),这些 API 存放于包 java.beans 中。

原来ActionForm序列化确实和web客户端服务器端交互原理没有任何关系,是JavaBean规范要求的,是我搞错了,被表象迷惑了,问题终于解决了,感谢细心的网友!

0 请登录后投票
   发表时间:2009-09-18  
声明:主帖对于struts FormBean为什么要序列化的问题的观点有误,为防止误导网友,特将主贴中关于对象序列化和最后的问题总结内容删除,只留下HTTP客户端和服务器端交互原理部分,特此声明!
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics