協議簡介
協議,自然語言里面就是契約,也是雙方或者多方經過協商達成的一致意見;
契約也即類似於合同,自然有甲方123...,乙方123...,哪些能做,哪些不能做;
通信協議,也即是雙方通過網絡通信必須遵從的一組約定;
計算機網絡的本質在於傳遞數據,協議自然是針對於數據的結構格式以及傳送規則的約定;
之前介紹過計算機網絡的發展,其中TCP/IP協議棧共分為四層,兩個程序端點數據的傳輸是U字形的
應用層
傳輸層
網絡層
網絡接口層
HTTP是工作在應用層的協議,所謂的工作在哪層,只不過是對底層的封裝程度而已;
HTTP協議是什么
HTTP協議是Tim(計算機發展系列提到過)發明的,也正是他完成了萬維網三大基礎技術的設計:命名方案(URI),通信協議(HTTP)和用來表示信息的標記語言(HTML);
回過神來仔細想想web的發展過程,web是B/S結構的,瀏覽器(B)通過網絡向服務器(S)請求數據,
有了TCP/IP協議以及Socket編程,你可以很容易的完成服務器與請求方的數據溝通;
但是信息的傳遞的重點在於信息本身,而不是這一次的數據交換,必須要能夠相互理解;
因為單純的數據交流並沒有任何意義,必須有對話的基礎,那就是"語言";
就好像你(請求方)在說普通話,水果店老板(服務器)在講英語,你們從早上交流到晚上可能並沒有有效的傳遞任何信息;
所以HTTP協議就是這樣一種用於瀏覽器客戶端與服務器交流的一種"語言";
他規定了對話的語法以及格式,有了HTTP協議,客戶端和服務器端就可以相互理解對方,才能達到信息交換的目的;
既然HTTP是為了WEB創造的,自然是請求獲取的一個過程,而且當時就是HTML
所以最初他就是這么簡單,獲取一個名為XXX的HTML文件
GET /index.html
1991年Tim寫了一篇關於HTTP的協議的文章,被看做是HTTP/0.9
地址:https://www.w3.org/Protocols/HTTP/AsImplemented.html
HTTP-Hypertext Transfer protocol ,超文本傳輸協議,他的名字完整的對自己進行了釋義:傳輸超文本HTML文件的協議;
HTTP協議的發展
最初的版本,看起來可能比較簡陋,他只能單獨的請求數據,連是不是請求出錯了都無法感知,顯然,這不可能持續滿足需求;
1996年 HTTP/1.0 版本發布
1.0是相對於0.9的大闊步發展,增加了很多內容,詳見RFC1945 https://tools.ietf.org/html/rfc1945
不再限制內容的格式只能是HTML,任何格式都可以;
除了GET還引入了POST 和 HEAD 豐富了瀏覽器客戶端和服務器的交互
HTTP請求和相應的格式信息也更加豐富,還增加了狀態碼等等內容
1997年1月,HTTP/1.1 版本發布,只比 1.0 版本晚了半年,1.1是1.0的升級優化版,重點在於完善優化
這也是目前一直在用的一個版本
HTTP協議的格式
HTTP默認的端口號為80,HTTPS的端口號為443,HTTP協議包括請求和響應
其中CRLF是回車換行
此圖片來自於<計算機網絡> ,首部也就是前面圖中的頭部 一個意思
請求和響應都包括:行/頭部/主體
請求行包括:方法/URL/版本號
響應行包括:版本號/狀態碼/描述
請求頭和響應頭都是KEY:VALUE的鍵值對形式,個數為n
頭部可以分成三個部分:請求/響應頭字段、通用頭字段、實體頭字段。
其中通用頭字段和實體頭字段部分內容也在響應部分有相同的定義。
請求體通常不用,響應體也不一定用;
HTTP請求方法
HTTP請求方法有下面幾種,常用的有GET、POST請求.
| GET | 請求指定的頁面信息,並返回實體主體。 |
| POST | 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。 |
| HEAD | 類似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭 |
| PUT | 從客戶端向服務器傳送的數據取代指定的文檔的內容。 |
| DELETE | 請求服務器刪除指定的資源。 |
| CONNECT | HTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器。 |
| OPTIONS | 允許客戶端查看服務器的性能。 |
| TRACE | 回顯服務器收到的請求,主要用於測試或診斷,還回測試的請求報文 |
HTTP狀態碼
三位數字表示,第一位表示類型
1XX 消息,服務器收到請求,需要請求者繼續執行操作
2XX 成功,操作被成功接收並處理
3XX 重定向,需要進一步的操作以完成請求
4XX 客戶端錯誤,請求包含語法錯誤或無法完成請求
5XX 服務器錯誤,服務器在處理請求的過程中發生了錯誤
| 100 | Continue | 繼續。客戶端應繼續其請求 |
| 101 | Switching Protocols | 切換協議。服務器根據客戶端的請求切換協議。只能切換到更高級的協議,例如,切換到HTTP的新版本協議 |
| 200 | OK | 請求成功。一般用於GET與POST請求 |
| 201 | Created | 已創建。成功請求並創建了新的資源 |
| 202 | Accepted | 已接受。已經接受請求,但未處理完成 |
| 203 | Non-Authoritative Information | 非授權信息。請求成功。但返回的meta信息不在原始的服務器,而是一個副本 |
| 204 | No Content | 無內容。服務器成功處理,但未返回內容。在未更新網頁的情況下,可確保瀏覽器繼續顯示當前文檔 |
| 205 | Reset Content | 重置內容。服務器處理成功,用戶終端(例如:瀏覽器)應重置文檔視圖。可通過此返回碼清除瀏覽器的表單域 |
| 206 | Partial Content | 部分內容。服務器成功處理了部分GET請求 |
| 300 | Multiple Choices | 多種選擇。請求的資源可包括多個位置,相應可返回一個資源特征與地址的列表用於用戶終端(例如:瀏覽器)選擇 |
| 301 | Moved Permanently | 永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今后任何新的請求都應使用新的URI代替 |
| 302 | Found | 臨時移動。與301類似。但資源只是臨時被移動。客戶端應繼續使用原有URI |
| 303 | See Other | 查看其它地址。與301類似。使用GET和POST請求查看 |
| 304 | Not Modified | 未修改。所請求的資源未修改,服務器返回此狀態碼時,不會返回任何資源。客戶端通常會緩存訪問過的資源,通過提供一個頭信息指出客戶端希望只返回在指定日期之后修改的資源 |
| 305 | Use Proxy | 使用代理。所請求的資源必須通過代理訪問 |
| 306 | Unused | 已經被廢棄的HTTP狀態碼 |
| 307 | Temporary Redirect | 臨時重定向。與302類似。使用GET請求重定向 |
| 400 | Bad Request | 客戶端請求的語法錯誤,服務器無法理解 |
| 401 | Unauthorized | 請求要求用戶的身份認證 |
| 402 | Payment Required | 保留,將來使用 |
| 403 | Forbidden | 服務器理解請求客戶端的請求,但是拒絕執行此請求 |
| 404 | Not Found | 服務器無法根據客戶端的請求找到資源(網頁)。通過此代碼,網站設計人員可設置"您所請求的資源無法找到"的個性頁面 |
| 405 | Method Not Allowed | 客戶端請求中的方法被禁止 |
| 406 | Not Acceptable | 服務器無法根據客戶端請求的內容特性完成請求 |
| 407 | Proxy Authentication Required | 請求要求代理的身份認證,與401類似,但請求者應當使用代理進行授權 |
| 408 | Request Time-out | 服務器等待客戶端發送的請求時間過長,超時 |
| 409 | Conflict | 服務器完成客戶端的PUT請求是可能返回此代碼,服務器處理請求時發生了沖突 |
| 410 | Gone | 客戶端請求的資源已經不存在。410不同於404,如果資源以前有現在被永久刪除了可使用410代碼,網站設計人員可通過301代碼指定資源的新位置 |
| 411 | Length Required | 服務器無法處理客戶端發送的不帶Content-Length的請求信息 |
| 412 | Precondition Failed | 客戶端請求信息的先決條件錯誤 |
| 413 | Request Entity Too Large | 由於請求的實體過大,服務器無法處理,因此拒絕請求。為防止客戶端的連續請求,服務器可能會關閉連接。如果只是服務器暫時無法處理,則會包含一個Retry-After的響應信息 |
| 414 | Request-URI Too Large | 請求的URI過長(URI通常為網址),服務器無法處理 |
| 415 | Unsupported Media Type | 服務器無法處理請求附帶的媒體格式 |
| 416 | Requested range not satisfiable | 客戶端請求的范圍無效 |
| 417 | Expectation Failed | 服務器無法滿足Expect的請求頭信息 |
| 500 | Internal Server Error | 服務器內部錯誤,無法完成請求 |
| 501 | Not Implemented | 服務器不支持請求的功能,無法完成請求 |
| 502 | Bad Gateway | 充當網關或代理的服務器,從遠端服務器接收到了一個無效的請求 |
| 503 | Service Unavailable | 由於超載或系統維護,服務器暫時的無法處理客戶端的請求。延時的長度可包含在服務器的Retry-After頭信息中 |
| 504 | Gateway Time-out | 充當網關或代理的服務器,未及時從遠端服務器獲取請求 |
| 505 | HTTP Version not supported | 服務器不支持請求的HTTP協議的版本,無法完成處理 |
HTTP頭部-通用頭字段
請求和響應都會用到的頭部字段
- Cache-Control 指定請求和響應遵循的緩存機制
- Connection 控制不在轉發給代理的首部也就是有些首部信息通過他控制刪除后轉發,另外就是是否持久連接1.1默認持久
- Date 報文創建的日期和時間 http1.1使用RFC1123中規定的格式
- Pragma 遺留字段 形式唯一 Pragma:no-cache,雖是通用,但僅用於請求,要求所有中間服務器不返回緩存的資源
- Trailer 事先說明報文主體之后記錄了哪些頭字段
- Transfer-Encoding 傳輸報文主體時采用的編碼方式
- Upgrade 檢測HTTP協議以及其他協議是否可以使用更高版本通信,參數還可以指定一個完全不同的通信協議
- Via 追蹤客戶端和服務器之間的請求和響應報文的傳輸路徑
- Warning 告知用戶一些與緩存相關的問題的警告
HTTP頭部-請求頭字段
從客戶端向服務器端發送請求時使用到的頭字段,補充了請求的附加內容,客戶端信息,響應內容優先級等信息
1.Accept
告知服務器,能夠處理的媒體類型以及媒體類型的相對優先級 可使用type/subtype的形式,一次指定多種類型
比如 text/html,text/plain,text/css………
2.Accept-Charset
告知服務器,能夠處理的字符集以及字符集的相對優先級
也可以一次指定多個
3.Accept-Encoding
告知服務器,支持的內容編碼以及內容編碼的相對優先級,可以一次性指定多種內容編碼 gzip,compress,deflate,identity
4.Accept-Language
告知服務器,能夠處理的自然語言集,比如中文 英文 ,以及自然語言的相對優先級,可以一次性指定多種自然語言集
5.Authorization
告知服務器,認證信息
6.Expect
告知服務器,期望出現的某種特定行為
7.From
告知服務器,電子郵件地址
8.Host
告知服務器,請求資源的主機名以及端口號,Host是請求頭字段里面,HTTP1.1唯一一個要求必須有的字段
形如If-Xxx的請求頭字段,都是條件字段,服務器會判斷這個條件,只有條件為真的時候才會執行請求
9.If-Match
告知服務器,匹配資源所用的實體標記ETag的值 如果使用*號,服務器將忽略不在比較
10.If-Modified-Since
告知服務器,指定的日期后資源發生了更新,服務器會接受響應 ,參數為日期時間
11.If-None-Match
與If-Match原理一樣,取值相反
12.If-Range
屬於附帶條件之一 字段值若是跟ETag或者更新日期時間匹配一致,那么作為范圍請求處理,否則返回全部資源
13.If-Unmodified-Since
原理同If-Modified 取值相反
14.Max-Forwards
通過TRACE或者OPTIONS,發送包含此字段的請求,以十進制形式指定可經過的服務器最大數目
15.Proxy-Authorization
認證相關
16.Range
對於只獲取部分資源的范圍請求,告知服務器資源的指定范圍,服務器接收Range處理后還會返回206 無法處理則會忽視,返回200以及全部資源
17.Referer
告知服務器請求的原始資源的URI
18.TE
告知服務器,客戶端能夠處理的響應的傳輸編碼方式以及相對優先級,注意是傳輸,傳輸中編碼
19.User-Agent
創建請求的瀏覽器和用戶代理名稱等信息傳達給服務器
HTTP頭部-響應頭字段
從服務器端返回響應時用到的頭部字段,補充了響應的附加內容
1.Accept-Ranges
告知客戶端,服務器是否能夠處理范圍請求,如果不能值為none,Accept-Ranges:none;否則是bytes
2.Age
告知客戶端,源服務器在多久前創建了響應,字段值單位為s,如果是緩存服務器值為緩存后的響應再次發起認證到認證完成的時間值,代理創建響應必須加上Age
3.Etag
告知客戶端實體標識,可以將資源以字符串形式唯一標識的方式,服務器會給每個資源創建ETag值,資源更新,Etag也需要更新
4.Location
將響應接收方引導至某個請求URI位置不同的資源,基本上字段會配合3XX,幾乎所有的瀏覽器接收到Location響應都會強制嘗試對已經提示的信息進行重定向
5.Proxy-authenticate
代理服務器需要的認證信息發送給客戶端
6.Retry-After
告知客戶端,多久后重新請求,主要配合503或者3xx Redirect響應一起使用
7.Server
告知客戶端,服務器上安裝的HTTP服務器應用程序信息
8.Vary
源服務器向代理服務器傳達對緩存進行控制的信息,
9.WWW-Authenticate
用於HTTP訪問認證
HTTP頭部-實體頭字段
針對請求和響應報文的實體部分使用的頭字段,用於補充內容的更新時間等與實體相關的信息
1.Allow
通知客戶端能夠支持Request-URI指定資源的所有HTTP方法,收到不支持的方法請求時,返回405 Method Not Allowed,還會把支持的方法寫入首部字段Allow返回
2.Content-Encoding
會告知客戶端 服務器 對實體的主體部分選用的內容編碼方式,指在不丟失信息的前提下進行壓縮
3.Content-Language
告知客戶端,實體主體使用的自然語言比如中文 英文
4.Content-Length
實體主體部分的大小,單位字節
5.Content-Location
給出與報文主體部分相對應的URI,和Location不同,本字段表示的是報文主體返回資源對應的URI
6.Content-MD5
MD5生成的值,目的在於檢查報文主體傳輸過程中是否保持完整,客戶端通過對報文主體執行相同的MD5算法然后比對,確認傳輸到達
7.Content-Range
針對范圍請求,返回響應時使用的首部字段,告知客戶端 作為響應返回的實體的 哪個部分符合范圍請求. 字節為單位
8.Content-Type
實體主體內對象的媒體類型,用type/subType設置
9.Expires
資源失效的日期告訴客戶端,接收到Expires的響應后會以緩存來應答,指定的時間值之前,響應的副本會一直保存,超過指定時間,緩存服務器會轉向源服務器,優先級比Cache-Control max-age低
為Cookies服務的頭部字段
Set-Cookie 開始狀態管理所使用的Cookie信息 響應頭字段
Cookie 服務器接收到的Cookie信息 請求頭字段
Set-Cookie 字段屬性
Name=value 鍵值對的形式 必須
expires=DATE 有效期,不指定默認為瀏覽器關閉
path=PATH 服務器上的文件目錄作為Cookie的適用對象,不指定默認為當前目錄
domain=域名 作為Cookies適用對象的域名,不指定默認為創建Cookie的服務器域名
Secure 僅僅HTTPS下才發送Cookie
HttpOnly 限制,js不能使用Cookie
模擬瀏覽器和服務器原理
說了那么多HTTP協議,其實終究也還只是個信息傳遞交互的一個格式.
所以說,你只要發送指定格式的數據到服務器,就能像瀏覽器一樣請求數據
只要能夠接受請求返回HTTP協議指定的格式的響應,瀏覽器就能解析數據
網絡編程離不開Socket,Socket也是一個IO流,只不過通過Socket實現的是客戶端與服務端的IO讀寫
服務器的I是客戶端的O
客戶端的I是服務器的O
下面的例子非常的簡單,當然也不怎么完善,但是你可以清晰地看到,協議,的作用,
//客戶端瀏覽器 import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { //建立客戶端Socket Socket s = new Socket("www.baidu.com",80); //獲取輸出流 客戶端的輸出流也即是服務端的輸入流 //也就是發送數據到服務器 PrintWriter out = new PrintWriter(s.getOutputStream(),true); out.println("GET /error.html HTTP/1.1"); out.println("Accept: */*"); out.println("Host: www.baidu.com"); out.println("Connection: close"); out.println(); out.println(); //接收服務器的響應信息 //客戶端的輸入流就是服務器輸出流 InputStream in = s.getInputStream(); //緩沖區 1024 byte[] buf = new byte[1024]; int len = in.read(buf); //打印信息 String str =new String(buf,0,len); System.out.println(str); s.close(); } }
//服務端 import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { //服務端socket ServerSocket ss = new ServerSocket(8080); //等待請求 Socket s = ss.accept(); System.out.println(s.getInetAddress().getHostAddress()+".....connected"); //獲取輸入流打印客戶端請求信息 InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); String text = new String(buf,0,len); System.out.println(text); //發送數據到客戶端 PrintWriter out = new PrintWriter(s.getOutputStream(),true); out.println("<font color='green' size='10'>welcome</font>"); s.close(); ss.close(); } }
如果有的瀏覽器打不開,請用IE瀏覽器,畢竟就隨便輸出了一條頭部信息等都沒有好好搞
HTTP協議總結:
所謂協議就是有固定格式結構,有約定語義;
大家都基於這種語義進行交流溝通;HTTP協議也是如此,他不關注具體的數據,只關心數據的格式以及語義;
所以只要你發送符合HTTP協議的指定格式的請求數據,你就能得到服務器的響應;
只要你返回符合HTTP協議的指定格式的響應數據,你就能正確發送信息到客戶端;
服務器端和瀏覽器(客戶端)通過HTTP這一協議進行數據交互,實現了服務器端與瀏覽器端的解耦
正是解耦,使得瀏覽器和服務器技術可以相互獨立發展;








