淺析Java web程序之客戶端和服務(wù)器端交互原理
a. TCP/IP整體構(gòu)架概述
TCP/IP協(xié)議并不完全符合 OSI的七層參考模型。傳統(tǒng)的開放式系統(tǒng)互連參考模型,是一種通信協(xié)議的7層抽象的參考模型,其中每一層執(zhí)行某一特定任務(wù)。該模型的目的是使各種硬件在相 同的層次上相互通信。這7層是:物理層、數(shù)據(jù)鏈路層、網(wǎng)路層、傳輸層、話路層、表示層和應(yīng)用層。而TCP/IP通訊協(xié)議采用了4層的層級結(jié)構(gòu),每一層都呼 叫它的下一層所提供的網(wǎng)絡(luò)來完成自己的需求。這4層分別為:
i. 應(yīng)用層:應(yīng)用程序間溝通的層,如超文本傳送協(xié)議(HTTP)、簡單電子郵件傳輸(SMTP)、文件傳輸協(xié)議(FTP)、網(wǎng)絡(luò)遠程訪問協(xié)議(Telnet)等。
ii. 傳輸層:在此層中,它提供了節(jié)點間的數(shù)據(jù)傳送服務(wù),如傳輸控制協(xié)議(TCP)、用戶數(shù)據(jù)報協(xié)議(UDP)等,TCP和UDP給數(shù)據(jù)包加入傳輸數(shù)據(jù)并把它傳輸?shù)较乱粚又校@一層負責(zé)傳送數(shù)據(jù),并且確定數(shù)據(jù)已被送達并接收。
iii. 互連網(wǎng)絡(luò)層:負責(zé)提供基本的數(shù)據(jù)封包傳送功能,讓每一塊數(shù)據(jù)包都能夠到達目的主機(但不檢查是否被正確接收),如網(wǎng)際協(xié)議(IP)。
iv. 網(wǎng)絡(luò)接口層:對實際的網(wǎng)絡(luò)媒體的管理,定義如何使用實際網(wǎng)絡(luò)(如Ethernet、Serial Line等)來傳送數(shù)據(jù)。
b. HTTP協(xié)議介紹:
i. HTTP是一種超文本傳送協(xié)議(HyperText Transfer Protocol),是一套計算機在網(wǎng)絡(luò)中通信的一種規(guī)則。在TCP/IP體系結(jié)構(gòu)中,HTTP屬于應(yīng)用層協(xié)議,位于TCP/IP協(xié)議的頂層
ii. HTTP是一種無狀態(tài)的的協(xié)議,意思是指 在Web 瀏覽器(客戶端)和 Web 服務(wù)器之間不需要建立持久的連接。整個過程就是當(dāng)一個客戶端向服務(wù)器端發(fā)送一個請求(request),然后Web服務(wù)器返回一個響應(yīng) (response),之后連接就關(guān)閉了,在服務(wù)端此時是沒有保留連接的信息。
iii. HTTP 遵循 請求/響應(yīng)(request/response) 模型的,所有的通信交互都被構(gòu)造在一套請求和響應(yīng)模型中。
iv. 瀏覽WEB時,瀏覽器通過HTTP協(xié)議與WEB服務(wù)器交換信息,Web服務(wù)器向Web瀏覽器返回的文件都有與之相關(guān)的類型,這些信息類型的格式由MIME定義。
c. 協(xié)議的java實現(xiàn)方式
不論是TCP/IP協(xié)議也好,還是HTTP協(xié)議也好,java都是通過套接字(java.net.Socket)來實現(xiàn)的,可以參考我的另一篇技術(shù)博客:一個項目看java TCP/IP Socket編程(1.3版)
2、HTTP報文接口及客戶端和服務(wù)器端交互原理
a. HTTP定義的事務(wù)處理由以下四步組成:
i. 建立連接:
例如我在瀏覽器里輸入 http://cuishen.iteye.com,客戶端請求這個地址時即打開了web服務(wù)器HTTP端口的一個套接字。因為在網(wǎng)絡(luò)中間作為傳遞數(shù)據(jù)的 實體介質(zhì)就是網(wǎng)線,數(shù)據(jù)實質(zhì)上是通過IO流進行輸出和輸入,這就不難理解我們?yōu)槭裁丛趯懸粋€Servlet的時候要引用 import java.io.*; 的原因 ,包括我們在向客戶端回發(fā)結(jié)果的時候要用到PrintWriter對象的println()方法。其實請求的這個地址還要加上端口號80,80可以不寫, 是因為瀏覽器默認的端口號是80。
在Java底層代碼中是這樣實現(xiàn)的,只不過它們已經(jīng)幫我們做了。
|
ii. 客戶端發(fā)送HTTP請求報文(request)
一旦建立了TCP連接,Web瀏覽器就會向Web服務(wù)器發(fā)送請求命令,是一個ASCII文本請求行,后跟0個或多個HTTP頭標(biāo),一個空行和實現(xiàn)請求的任意數(shù)據(jù)。
1)請求行
請求行由三個標(biāo)記組成:請求方法、請求URL和HTTP版本,中間用空格分開
例如: GET cuishen.iteye.com/blog/242842 HTTP/1.1
HTTP規(guī)范定義了8種可能的請求方法:(最常見的就是 GET 和 POST 兩種方法)
● GET -- 檢索URI中標(biāo)識資源的一個簡單請求
● HEAD -- 與GET方法相同,服務(wù)器只返回狀態(tài)行和頭標(biāo),并不返回請求文檔
● POST -- 服務(wù)器接受被寫入客戶端輸出流中的數(shù)據(jù)的請求
● PUT -- 服務(wù)器保存請求數(shù)據(jù)作為指定URI新內(nèi)容的請求
● DELETE -- 服務(wù)器刪除URI中命名的資源的請求
● OPTIONS -- 關(guān)于服務(wù)器支持的請求方法信息的請求
● TRACE -- Web服務(wù)器反饋Http請求和其頭標(biāo)的請求
● CONNECT -- 已文檔化但當(dāng)前未實現(xiàn)的一個方法,預(yù)留做隧道處理
2)請求頭標(biāo)
請求頭標(biāo):由key :value 健值組成,每行一對。請求頭標(biāo)用來通知服務(wù)器有關(guān)客戶端的功能和標(biāo)識。
HOST -- 請求的哪一個服務(wù)器端地址,主地址,比如:我的技術(shù)blog:cuishen.iteye.com
User-Agent -- 用戶即客戶端可以使用的瀏覽器 ,如: Mozilla/4.0
Accept -- 即客戶端可以接受的MIME 類型列表,如image/gif、text/html、application/msword
Content-Length -- 只適用于POST請求,以字節(jié)給出POST數(shù)據(jù)的尺寸
3)空行
發(fā)送回車符和退行,通知服務(wù)器以下不再有頭標(biāo)。
4)請求數(shù)據(jù)
使用POST傳送數(shù)據(jù),最常使用的是Content-Type和Content-Length頭標(biāo)。
請求報文總結(jié):
我們可以這樣寫出一個標(biāo)準(zhǔn)的 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()請求的數(shù)據(jù)) |
這上面的一個例子意思是:
我要去訪問的服務(wù)器端的地址是cuishen.iteye.com/ 它下面的資源 /blog/242842
連起來就是: cuishen.iteye.com/blog/242842
這個頁面用的是 HTTP1.1 規(guī)范,我的瀏覽器版本是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">
(c).空行:最后一個響應(yīng)頭標(biāo)之后是一個空行,發(fā)送回車符和退行,表明服務(wù)器以下不再有頭標(biāo)。
(d).響應(yīng)數(shù)據(jù):HTML文檔和圖像等,也就是HTML本身。out.println("<html>......");寫到客戶端。
|
iv. 服務(wù)器端關(guān)閉連接,客戶端解析回發(fā)響應(yīng)報文,恢復(fù)頁面
1)瀏覽器先解析狀態(tài)行,查看請求是否成功的狀態(tài)代碼--HTTP響應(yīng)碼:404 400 200 ....
2)解析每一個響應(yīng)頭標(biāo),如:
ContentType: text/html;charset=gb2312 Content-Length: 122 --- 響應(yīng)中的字節(jié)數(shù),只在瀏覽器使用永久(Keep-alive)HTTP連接時需要。 |
3)讀取響應(yīng)數(shù)據(jù)HTML,根據(jù)標(biāo)簽<html></html>中的內(nèi)容恢復(fù)標(biāo)準(zhǔn)的HTML格式頁面或者其它。
4)一個HTML 文檔可能包含其它的需要被載入的資源,瀏覽器會識別,并對這些資源再進行額外的請求,這個過程可以是循環(huán)的方式一直到所有的數(shù)據(jù)都按照響應(yīng)頭標(biāo)中規(guī)定的格式恢復(fù)到頁面中。
5)數(shù)據(jù)傳送完畢,服務(wù)器端關(guān)閉連接,即無狀態(tài)協(xié)議。
3、總結(jié)
不要被高深的名詞和理論嚇到,其實HTTP客戶端和服務(wù)器端的交互原理很簡單:即先是瀏覽器和服務(wù)器端建立Socket無狀態(tài)連接,也就是短連 接,然后通過IO流進行報文信息(這個報文是嚴(yán)格遵循HTTP報文接口的)的交互,最后會話結(jié)束后就關(guān)閉連接。對于這些底層的協(xié)議和報文的打包解包交互的 實現(xiàn),其實java和瀏覽器早都已經(jīng)封裝好了,程序員只要專注于業(yè)務(wù)邏輯的實現(xiàn)就行啦,這些都不必關(guān)心!!