一、What is HTTP ?
1. 協議概述
HTTP
(HyperText Transfer Protocol,超文本傳輸協議) 是互聯網上應用最為廣泛的一種網絡協議,設計 HTTP
最初的目的是為了提供一種發布和接收HTML頁面的方法
HTTP
協議中現今廣泛使用的一個版本是1999年6月公布的 HTTP1.1
,而2015年5月發表的HTTP/2
取代 HTTP1.1
成為 HTTP
新的實現標準
通常,由 HTTP
客戶端發起一個請求,創建一個到服務器指定端口(默認是80端口
)的 TCP
連接。HTTP
服務器則在那個端口監聽客戶端的請求。一旦收到請求,服務器會向客戶端返回一個狀態,比如 HTTP/1.1 200 OK
,以及返回的內容,如請求的文件、錯誤消息、或者其它信息
二、請求信息 (Request Message)
發出的請求信息包括以下幾個:
- 請求行
例如GET /images/logo.gif HTTP/1.1
,表示從/images
目錄下請求logo.gif
這個文件 - 請求頭
例如Accept-Language: en
- 空行
- 其他消息體
請求行和標題必須以<CR><LF>作為結尾
空行內必須只有<CR><LF>而無其他空格
在HTTP/1.1協議中,所有的請求頭,除Host外,都是可選的
1. 請求方法
HTTP/1.1
中共定義了8種方法(動作)來以不同方式操作指定的資源
-
GET
:向指定的資源發出“顯示”請求,使用GET
方法應該只用在讀取數據 -
POST
:向指定資源提交數據,請求服務器進行處理(例如提交表單或者上傳文件)
數據被包含在請求本文中。這個請求可能會創建新的資源或修改現有資源,或二者皆有 -
HEAD
:與GET
方法一樣,都是向服務器發出指定資源的請求
只不過服務器將不傳回資源的本文部分。它的好處在于,使用這個方法可以在不必傳輸全部內容的情況下,就可以獲取其中“關于該資源的信息”(元信息或稱元數據) -
OPTIONS
:這個方法可使服務器傳回該資源所支持的所有HTTP
請求方法。
用'*'來代替資源名稱,向Web服務器發送OPTIONS
請求,可以測試服務器功能是否正常運作 -
PUT
:向指定資源位置上傳其最新內容 -
DELETE
:請求服務器刪除Request-URI
所標識的資源 -
TRACE
:回顯服務器收到的請求,主要用于測試或診斷 -
CONNECT
:HTTP/1.1
協議中預留給能夠將連接改為管道方式的代理服務器。
通常用于SSL
加密服務器的鏈接(經由非加密的HTTP
代理服務器)
** 方法名稱是區分大小寫的 **:
- 當某個請求所針對的資源不支持對應的請求方法的時候,服務器應當返回狀態碼
405(Method Not Allowed)
- 當服務器不認識或者不支持對應的請求方法的時候,應當返回狀態碼
501(Not Implemented)
- HTTP服務器至少應該實現
GET
和HEAD
方法,其他方法都是可選的- 安全超文本連接協議使用
https://
代替http://
2. 狀態碼
所有HTTP響應的第一行都是狀態行,依次是當前 HTTP
版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔。
狀態代碼的第一個數字代表當前響應的類型:
-
1xx
消息 —— 請求已被服務器接收,繼續處理 -
2xx
成功 —— 請求已成功被服務器接收、理解、并接受 -
3xx
重定向 —— 需要后續操作才能完成這一請求 -
4xx
請求錯誤 —— 請求含有詞法錯誤或者無法被執行 -
5xx
服務器錯誤 —— 服務器在處理某個正確請求時發生錯誤
3. 舉個栗子
下面是一個HTTP客戶端與服務器之間會話的例子,運行于 www.google.com
,端口 80
客戶端請求:
GET / HTTP/1.1
Host: www.google.com
末尾有一個空行
第一行:指定方法、資源路徑、協議版本
第二行:在1.1版里必帶的一個header作用指定主機
服務器響應:
HTTP/1.1 200 OK
Content-Length: 3059
Server: GWS/2.0
Date: Sat, 11 Jan 2003 02:44:04 GMT
Content-Type: text/html
Cache-control: private
Set-Cookie: PREF=ID=73d4aef52e57bae9:TM=1042253044:LM=1042253044:S=SMCc_HRPCQiqy
X9j; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Connection: keep-alive
(緊跟著一個空行,并且由HTML格式的文本組成了Google的主頁)
- 在
HTTP1.0
,單一TCP
連接內僅執行一個“客戶端發送請求—服務器發送應答”周期,之后釋放TCP
連接。 - 在
HTTP1.1
優化支持持續活躍連接:客戶端連續多次發送請求、接收應答;批量多請求時,同一TCP
連接在活躍Keep-Live
間期內復用,避免重復TCP
初始握手活動,減少網絡負荷和響應周期。此外支持應答到達前繼續發送請求(通常是兩個),稱為“流線化”(stream)。
4. 通用頭域
通用頭域包含請求和響應消息都支持的頭域,通用頭域包含:
Cache-Control
頭域:指定請求和響應遵循的緩存機制
在請求消息或響應消息中設置Cache-Control
并不會修改另一個消息處理過程中的緩存處理過程-
請求時的緩存指令包括:
-
no-cache
:指示響應可被任何緩存區緩存 -
no-store
:在請求消息中發送將使得請求和響應消息都不使用緩存,可防止重要的信息被無意的發布 -
max-age
:指示客戶機可以接收生存期不大于指定時間(以秒為單位)的響應 -
max-stale
:指示客戶機可以接收超出超時期間的響應消息。
如果指定max-stale消息的值,那么客戶機可以接收超出超時期指定值之內的響應消息 -
min-fresh
:指示客戶機可以接收響應時間小于當前時間加上指定時間的響應 only-if-cached
-
-
響應消息中的指令包括:
-
public
:指示響應可被任何緩存區緩存 private
no-cache
no-store
no-transform
must-revalidate
proxy-revalidate
max-age
-
Connection
DateDate
頭域:頭域表示消息發送的時間,時間的描述格式由rfc822定義例如,
Date:Mon,31Dec200104:25:57GMT
Date
描述的時間表示世界標準時,換算成本地時間,需要知道用戶所在的時區。Pragma
頭域:用來包含實現特定的指令最常用的是
Pragma:no-cache
在 HTTP/1.1 協議中,它的含義和
Cache- Control:no-cache
相同Transfer-Encoding
頭域Upgrade
頭域Via
頭域
上面總結的是“通用頭域”,我們先來看下一個典型的請求信息:
GET / HTTP/1.1
Host: baidu.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: BDUSS=aaaaa; BAIDUID=bbbbb:FG=1; PSTM=1459694957; BDRCVFR[loys_9vxHFf]=mk3SLVN4HKm; BIDUPSID=ccccc; pgv_pvi=9192257536; pgv_si=s6465831936; H_PS_PSSID=ddddd
上面的第一行表示HTTP客戶端(可能是瀏覽器、下載程序)通過GET方法獲得指定URL下的文件。接下來,我們來分析下“ 請求頭域 ”
5. 請求頭域
-
Host
頭域:指定請求資源的Intenet主機和端口號 - 必須表示請求url的原始服務器或網關的位置
- HTTP/1.1請求必須包含主機頭域,否則系統會以400狀態碼返回
-
Referer
頭域:允許客戶端指定請求uri的源資源地址 - 這可以允許服務器生成回退鏈表,可用來登陸、優化cache等
- 也允許廢除的或錯誤的連接由于維護的目的被追蹤
- 如果請求的uri沒有自己的uri地址,Referer不能被發送
- 如果指定的是部分uri地址,則此地址應該是一個相對地址
-
Range
頭域:請求實體的一個或者多個子范圍 - 例如
- 表示頭500個字節:bytes=0-499
- 表示第二個500字節:bytes=500-999
- 表示500字節以后的范圍:bytes=500-
- 第一個和最后一個字節:bytes=0-0,-1
- 同時指定幾個范圍:bytes=500-600,601-999
- 但是服務器可以忽略此請求頭,如果無條件
GET
包含Range
請求頭,響應會以狀態碼206(PartialContent)
返回而不是以200 (OK)
-
User-Agent
頭域:內容包含發出請求的用戶信息
三、響應消息(Response Message)
1. 響應頭
我們先來看一個“請求百度首頁”的響應頭:
HTTP/1.1 200 OK
Date: Sun, 03 Apr 2016 15:44:32 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: Keep-Alive
Cache-Control: private
Expires: Sun, 03 Apr 2016 15:44:32 GMT
Content-Encoding: gzip
Server: BWS/1.1
X-UA-Compatible: IE=Edge,chrome=1
BDPAGETYPE: 2
BDQID: 0xb2584dee0005f8ac
BDUSERID: 801624962
Set-Cookie: BDSVRTM=147; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=aaaaa; path=/; domain=.baidu.com
響應頭的第一行為右邊的格式:
HTTP-Version Status-Code Reason-Phrase
HTTP- Version
:表示支持的HTTP版本
例如為HTTP/1.1Status- Code
:是一個三個數字的結果代碼(可參考前面總結的“狀態碼”部分)
主要用于機器自動識別,第一個數字定義響應的類別Reason-Phrase
:給Status-Code
提供一個簡單的文本描述
主要用于幫助用戶理解Location
響應頭:用于重定向接收者到一個新URI地址Server
響應頭:包含處理請求的原始服務器的軟件信息。
此域能包含多個產品標識和注釋,產品標識一般按照重要性排序
2. 實體
請求消息 和 響應消息 都可以包含實體信息,實體信息一般由 實體頭域 和 實體 組成
實體頭包括:
Allow | Content- Base | Content-Encoding | |
Content-Language | Content-Length | Content-Location | |
Content-MD5 | Content-Range | Content-Type | |
Etag | Expires | Last-Modified | |
extension-header |
-
Content-Type
實體頭:向接收方指示實體的介質類型 - 指定
HEAD
方法送到接收方的實體介質類型 - 或
GET
方法發送的請求介質類型 -
Content-Range
實體頭:指定整個實體中的一部分的插入位置,也指示了整個實體的長度 - 在服務器向客戶返回一個部分響應,它必須描述響應覆蓋的范圍和整個實體長度
- 一般格式:
Content-Range:bytes-unit first-byte-pos-last-byte-pos/entity-legth
- 例如,傳送頭500個字節次字段的形式:
Content-Range:bytes0- 499/1234
-
Content-Range
表示傳送的范圍,Content-Length
表示實際傳送的字節數 -
Last-modified
實體頭:指定服務器上保存內容的最后修訂時間
3. 響應頭
Allow
:服務器支持哪些請求方法(如GET
、POST
等)Content-Encoding
:文檔的編碼(Encode)方法只有在解碼之后才可以得到
Content-Type
頭指定的內容類型利用
gzip
壓縮文檔能夠顯著地減少HTML
文檔的下載時間Java的
GZIPOutputStream
可以很方便地進行gzip
壓縮,但只有Unix上的Netscape
和Windows
上的IE 4、IE 5才支持它。因此,
Servlet
應該通過查看Accept-Encoding
頭(即request.getHeader("Accept- Encoding")
)檢查瀏覽器是否支持gzip
,為支持gzip
的瀏覽器返回經gzip
壓縮的HTML
頁面,為其他瀏覽器返回普通頁面。Content-Length
:表示內容長度只有當瀏覽器使用持久HTTP連接時才需要這個數據
Content-Type
:表示后面的文檔屬于什么MIME類型Servlet
默認為text/plain
,但通常需要顯式地指定為text/html
由于經常要設置
Content-Type
,因此HttpServletResponse
提供了一個專用的方法setContentTyep
Date
:當前的GMT時間你可以用
setDateHeader
來設置這個頭以避免轉換時間格式的麻煩。Expires
:應該在什么時候認為文檔已經過期,從而不再緩存它?Last-Modified
:文檔的最后改動時間。客戶可以通過
If-Modified-Since
請求頭提供一個日期,該請求將被視為一個條件GET
,只有改動時間遲于指定時間的文檔才會返回,否則返回一個304(Not Modified)
狀態。Last-Modified
也可用setDateHeader方法來設置。Location
:表示客戶應當到哪里去提取文檔Location
通常不是直接設置的,而是通過HttpServletResponse
的sendRedirect
方法,該方法同時設置狀態代碼為302
。Refresh
:表示瀏覽器應該在多少時間之后刷新文檔,以秒計除了刷新當前文檔之外,你還可以通過
setHeader("Refresh", "5; URL=http://host/path")
讓瀏覽器讀取指定的頁面。 注意這種功能通常是通過設置HTML
頁面HEAD
區的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">
實現,這是因為,自動刷新或重定向對于那些不能使用CGI
或Servlet
的 HTML編寫者十分重要但是,對于
Servlet
來說,直接設置Refresh
頭更加方便注意
Refresh
的意義是“N秒之后刷新本頁面或訪問指定頁面”,而不是“每隔N秒刷新本頁面或訪問指定頁面”。因此,連續刷新要求每次都發送一個
Refresh
頭,而發送204
狀態代碼則可以阻止瀏覽器繼續刷新,不管是使用Refresh
頭還是<META HTTP-EQUIV="Refresh" ...>
注意:
Refresh
頭不屬于HTTP 1.1
正式規范的一部分,而是一個擴展,但Netscape
和IE
都支持它Server
:服務器名Servlet
一般不設置這個值,而是由Web
服務器自己設置Set-Cookie
:設置和頁面關聯的CookieServlet
不應使用response.setHeader("Set-Cookie", ...)
,而是應使用HttpServletResponse
提供的專用方法addCookie
四、Cookie
某些網站為了辨別用戶身份而儲存在用戶本地終端(Client Side)上的數據(通常經過加密)
1. 分類
Cookie
總是保存在客戶端中,按在客戶端中的存儲位置可分為
內存Cookie
-
內存Cookie
由瀏覽器維護,保存在內存中,瀏覽器關閉后就消失了,其存在時間是短暫的 硬盤Cookie
-
硬盤Cookie
保存在硬盤里,有一個過期時間,除非用戶手工清理或到了過期時間,硬盤Cookie
不會被刪除,其存在時間是長期的
所以,按存在時間,可分為 非持久Cookie
和 持久Cookie
2. 用途
因為 HTTP
協議是無狀態的,即服務器不知道用戶上一次做了什么,這嚴重阻礙了交互式 Web
應用程序的實現。Cookie就是用來繞開 HTTP
的無狀態性的“額外手段”之一。服務器可以設置或讀取 Cookies
中包含信息,借此維護用戶跟服務器會話中的狀態
3. 應用場景:
- 當登錄一個網站時,網站往往會請求用戶輸入用戶名和密碼,并且用戶可以勾選“下次自動登錄”
- 如果勾選了,那么下次訪問同一網站時,用戶會發現沒輸入用戶名和密碼就已經登錄了
- 這正是因為前一次登錄時,服務器發送了包含登錄憑據(用戶名加密碼的某種加密形式)的
Cookie
到用戶的硬盤上 - 第二次登錄時,(如果該
Cookie
尚未到期)瀏覽器會發送該Cookie
,服務器驗證憑據,于是不必輸入用戶名和密碼就讓用戶登錄了
4. Cookie的缺陷
-
Cookie
會被附加在每個HTTP
請求中,所以無形中增加了流量 - 由于在HTTP請求中的
Cookie
是明文傳遞的,所以安全性成問題(除非用HTTPS
) -
Cookie
的大小限制在4KB左右。對于復雜的存儲需求來說是不夠用的
5. 識別功能
- 如果在一臺計算機中安裝多個瀏覽器,每個瀏覽器都會以獨立的空間存放
Cookie
- 因為
Cookie
中不但可以確認用戶信息,還能包含計算機和瀏覽器的信息,所以一個用戶使用不同的瀏覽器登錄或者用不同的計算機登錄,都會得到不同的Cookie
信息 - 另一方面,對于在同一臺計算機上使用同一瀏覽器的多用戶群,
Cookie
不會區分他們的身份,除非他們使用不同的用戶名登錄。
參考文章:
[1] 維基百科:超文本傳輸協議
[2] 維基百科:Cookie
[2] madfrag:HTTP響應頭信息和請求頭信息詳解