目錄
- http協議是個什么東西
- http的請求類型都有哪些
- 常見的HTTP首部
- HTTP請求體
- HTTP響應體
- HTTP常見的響應狀態碼
- HTTP的cookieg管理
HTTP協議
HTTP是一種通用的網絡數據傳輸格式,它的傳輸內容不僅僅局限于HTML文件或者圖片,所有可以用字節序列表示的數據都可以使用HTTP進行傳輸。
HTTP通過TCP/IP進行數據傳輸,如果忽略底層的TCP協議的握手和揮手的細節,對于從客戶端到服務器的每一個請求和請求的響應,在HTTP1.0有下面幾個步驟:
- 默認情況下,客戶端在端口80開啟與服務器的一個TCP連接,當然也可以指定其他的端口。
- 客戶端向服務器發送消息,請求指定路徑上的資源。一個HTTP請求包括一個首部,可選項包括一個空行和這次請求的數據。
- 服務器向客戶端發送響應。響應以響應碼開頭,接著是包含元數據的首部,可選項包括一個空行以及所請求的文檔數據或者錯誤信息。
- 服務器關閉TPC連接。
在HTTP1.1(目前最常用的就是HTTP1.1)以及以后的HTTP版本中,可以通過一個TCP連接連續發送多個請求和接收多個響應。
也就是說,上面的1和4步驟中間的2和3步驟可以反復執行多次。另外,HTTP1.1中,請求數據和響應數據可以分塊發送,提高了擴展性。
HTTP請求方法
HTTP請求方法 | 描述 | 是否安全 | 是否冪等 |
---|---|---|---|
GET | 通常用于請求服務器獲取某個資源 | 是 | 是 |
HEAD | 類似于GET,但是響應結果中不包含響應體,只包含協議信息和首部,通常用于測試資源是否存在或者是否被修改 | 是 | - |
POST | 客戶端向服務器提交數據(支持HTML的表單數據),可能會導致新的資源的建立或者已有資源的修改 | 否 | 否 |
PUT | 從客戶端向服務器傳送的數據取代指定的文檔的內容(全部取代) | 否 | 是 |
PATCH | 客戶端向服務器傳送的數據取代指定的文檔的內容(部分取代) | 否 | 是 |
TRACE | 回顯客戶端請求服務器的原始請求報文,用于"回環"診斷 | 是 | - |
OPTIONS | 請求服務器獲取服務器支持的各種功能,可以詢問服務器支持什么類型的HTTP方法,一般用于性能測試 | 是 | - |
DELETE | 請求服務器刪除指定的資源 | 否 | 否 |
安全 : 意味著使用該種HTTP請求方法不會發生任何數據的修改或者更新動作,也就是請求多次也不會影響到資源的狀態。
冪等 : 意味著使用該HTTP請求方法請求多次HTTP調用,無論調用多少次,請求結果或者資源的狀態是一樣的。
HTTP方法的安全性和冪等性是我們在設計HTTP接口時候需要重點考慮的兩個因素。
上面提到的POST和PUT方法的功能可以理解為相同的,兩者的主要區別在于POST不是冪等的,而PUT是冪等的。
在目前的Web開發中,POST方法已經被濫用,一般很少人會使用PUT,除非是推崇RESTFUL風格編程。
PUT方法和PATCH方法的功能類似,都是用客戶端請求的數據去替換掉服務器中指定文檔中的內容,不過PUT方法是全部替換,而PATCH方法是部分替換。
常見的HTTP首部
字段 | 首部類型 | 描述 |
---|---|---|
User-Agent | 請求 | 用戶代理,用于告知服務器當前客戶端使用的是什么瀏覽器 |
Host | 請求 | 用于指定接收該請求的服務器的主機名和端口號 |
Accept-Charset | 請求 | 告知服務器客戶端可以接收和處理哪些字符集 |
Accept-Encoding | 請求 | 告知服務器客戶端可以接收和處理哪些編碼方式 |
Accept-Language | 請求 | 告知服務器客戶端可以接收和處理哪些語言 |
Accept | 請求 | 告知服務器客戶端可以接收和處理哪些媒體類型 |
Referer | 請求 | 提供了包含當前請求的URL的文檔的URL |
Cookie | 請求 | 客戶端通過它向服務器傳送一個或者多個令牌,原則上Cookie并不是安全的首部,Cookie的內容也會緩存在客戶端。 |
Cache-Control | 請求 | 告知服務器對當前的請求的響應結果進行緩存相關操作 |
Content-Type | 通用 | 告知服務器或者客戶端當前請求或者響應結果的內容(媒體)類型 |
Content-Length | 通用 | 告知服務器或者客戶端當前請求或者響應數據體的長度 |
Connection | 請求 | 否需要持久連接,如果指定為Keep-Alive,可以提供持久連接 |
Origin | 請求 | 指明當前的請求是一個針對跨域資源共享的請求 |
Access-Control-Allow-Origin | 響應 | 表示服務器允許的該跨域資源共享的請求來源 |
Server | 響應 | 用于告知客戶端服務器的相關信息 |
Set-Cookie | 響應 | Cookie對應,表示服務器設置成功的Cookie |
Content-Encoding | 響應 | Accept-Encoding對應,用于服務器告知客戶端當前響應結果的內容編碼 |
Content-Language | 響應 | 與Accept-Language對應,用于服務器告知客戶端當前響應結果的內容語言 |
其中 Accept的值可以是以下八種頂級的類型
text/* 表示人可讀的文字。
image/* 表示圖片。
model/* 表示3D模型,如VRML文件。
audio/* 表示音頻。
video/* 表示多媒體圖片、視頻,也可能是音頻。
application/* 表示二進制數據。
message/* 表示協議特定的信封,如Email消息和HTTP響應。
muitipart/* 表示多個文檔和資源的容器。
HTTP請求體
如果采用GET請求方法,只需要向遠處服務器提供URL,URL中的路徑和查詢字符串就可以匹配到需要查詢的資源。
但是URL中無法提供詳細的客戶端信息,像POST和PUT這些請求方法所攜帶的數據體有可能比較大。
因此HTTP需要請求體。HTTP請求體包括下面四個部分:
- 一個起始請求行,包括HTTP方法、路徑、查詢字符串以及HTTP版本。
- HTTP請求的首部。
- 一個空行(兩個連續的回車或者換行對)。
- 請求數據體。
GET /wp-admin/admin-ajax.php?postviews_id=23996&action=postviews&_=1538708851063 HTTP/1.1
Host: www.importnew.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36
Referer: http://www.importnew.com/23996.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
postviews_id=23996&action=postviews&_=1538708851063
HTTP響應體
響應體和請求體的格式類似,主要是返回服務器的響應數據到客戶端,包括服務器的一些信息和響應數據體。HTTP響應體主要包括下面的四個部分:
1、一個起始響應行,包括HTTP版本、狀態碼、狀態碼描述。
2、HTTP響應的首部。
3、一個空行(兩個連續的回車或者換行對)。
4、響應數據體。
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 05 Oct 2018 03:07:37 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=2
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.3
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
2995
Keep-Alive
在使用HTTP1.0的時候會為每個請求打開一個新的TCP連接,實際上,這導致了一個典型Web會話中打開和關閉所有連接所花費的事件遠遠大于實際傳輸數據所消耗的時間,特別是響應結果包含很多小文檔的會話。對于使用SSL或者TLS加密的HTTPS連接,這個問題更加嚴重,因為建立一個安全的Socket的握手過程遠比建立常規的Socket需要更多的工作。
在HTTP1.1和后面的版本中,服務器不必在返送響應之后就關閉連接。已經建立的連接可以保持打開,在同一個Socket上等待來自客戶端的新請求。簡單來說,就是可以在一個TCP連接上連續發送多個請求和連續進行多個請求的響應。
客戶端可以在HTTP請求首部中添加一個Connection請求頭,指定值為Keep-Alive,這樣就能實現Socket的重用:
Connection: Keep-Alive
HTTP1.1或者之后的版本,Keep-Alive是默認開啟的,不需要顯式指定,如果需要關閉可以設置為close:
Connection: close
一旦開啟了Keep-Alive,服務器在關閉一個Socket連接之前,如果有新的客戶端再次連接到服務器,那么就是重用Socket。在JDK中可以通過系統屬性來控制如果使用HTTP的Keep-Alive:
http.keepAlive:默認值為true,默認開啟HTTP的Keep-Alive。
http.maxConnections:同時保持打開的Socket數量的最大值,默認值為5。
http.keepAlive.remainingData:默認值為false,如果設置為true,則JDK在丟棄連接之后會完成剩余數據的清理。
sun.net.http.errorstream.enableBuffering:默認值為false,如果設置為true,則嘗試緩存400和500狀態碼的相對小的錯誤流,從而能釋放連接以備后續使用。
sun.net.http.errorstream.bufferSize:為緩存錯誤流的緩沖區的字節大小,默認值為4096字節,只有上一項為true的時候才有意義。
sun.net.http.errorstream.timeout:默認值為300ms,讀取錯誤流超時的毫秒數。
常見的HTTP狀態碼
簡單的說
- 響應碼100-199表示一個提供信息的響應。
- 響應碼200-299表示請求成功。
- 響應碼300-399表示重定向。
- 響應碼400-499表示一個客戶端引發的錯誤。
- 響應碼500-599表示一個服務器引發的錯誤。
狀態碼 | 狀態碼消息 | 含義 | HttpURLConnection中的常量 | 簡單描述 | ||
---|---|---|---|---|---|---|
1xx | - | 信息狀態碼。 | - | 不常見,暫不考慮 | ||
100 | Continue | 服務器準備接受請求主體,客戶端發送請求主體;這允許客戶端在請求發送大量數據之前詢問服務器是否接受請求。 | - | 不常見,暫不考慮 | ||
101 | Switching | Protocols | 服務器接受客戶端在Upgrade首部字段中要求改變應用的協議請求,如從HTTP轉換為WebSockets。 | - | 不常見,暫不考慮 | |
2xx | - | 表示請求成功。 | - | - | ||
200 | OK | 最常見的響應碼,代表請求成功。如果請求方法是GET或者POST,所請求的數據與正常的首部都包含在響應體中。如果請求方法是HEAD,則只包含首部信息。 | HTTP_OK | 處理請求成功 | ||
201 | Created | 服務器已經在響應體中指定的URL創建了對應的資源。客戶端現在應當嘗試加載該URL。這個響應碼只在響應POST請求時發送。 | HTTP_CREATED | 創建成功 | ||
202 | Accepted | 表示請求已經被處理,但是處理尚未結束,所以不會返回任何響應數據。 | HTTP_ACCEPTED | 接受請求 | ||
203 | Non-Authoritative | Information | 由緩存代理或者其他本地源返回資源的表示,不能保證是最新的。 | HTTP_NOT_AUTHORITATIVE | 無權威的返回結果 | |
204 | No | Content | 服務器已經成功處理了該請求,但是沒有信息發回給客戶端。一般是由于服務器上的表單處理邏輯的問題,只接收數據不返回數據。 | HTTP_NO_CONTENT | 無返回內容 | |
205 | Reset | Content | 服務器已經成功處理了該請求,但是沒有信息發回給客戶端。客戶端應該清除發送請求的表單信息。 | HTTP_RESET | 重置內容 | |
206 | Partial | Content | 服務器返回客戶端請求的資源的部分內容,而不是整個文檔。 | HTTP_PARTIAL | 部分內容 | |
3xx | - | 重定向。 | - | - | ||
300 | Multiple | Choices | 服務器為所請求的文檔提供一組不同的表示。 | HTTP_MULT_CHOICE | 多重選擇 | |
301 | Moved | Permanently | 資源已經移動到一個新的URL。客戶端應當自動加載這個URL的資源。 | HTTP_MOVE_PERM | 永久移動 | |
302 | Moved | Temporarity | 資源暫時移動到一個新的URL,但其位置在不久的將來還會再次改變。 | HTTP_MOVE_TEMP | 臨時移動 | |
4xx | - | 客戶端錯誤 | - | - | ||
400 | Bad | Request | 客戶端向服務器發出的請求使用了不正確的語法。 | HTTP_BAD_REQUEST | 錯誤請求 | |
401 | Unauthorized | 訪問這個URL需要身份驗證,一般是用戶名和口令。 | HTTP_UNAUTHORIZED | 未授權 | ||
403 | Forbidden | 服務器理解請求,但是有意拒絕進行處理。 | HTTP_FORBIDDEN | 禁止訪問 | ||
404 | Not | Found | 最常見的錯誤響應,指示服務器找不到所請求的資源。 | HTTP_NOT_FOUND | 未找到資源 | |
405 | Method | Not | Allowed | 請求方法不支持用于請求指定的資源。 | HTTP_BAD_METHOD | 方法禁用 |
406 | Not | Acceptable | 所請求的資源不能以客戶端希望的格式提供,客戶端期望的格式由請求HTTP首部Accept字段指定。 | HTTP_NOT_ACCEPTABLE | 不接受 | |
5xx | - | 服務端錯誤 | - | - | ||
500 | Internale | Server | Error | 服務器內部異常。 | HTTP_SERVER_ERROR | 服務器異常 |
501 | Not | Implemented | 服務器不具備完成請求的功能。 | HTTP_NOT_IMPLEMENTED | 尚未實現 | |
502 | Bad | Gateway | 服務器作為網關或代理,從上游服務器收到無效響應。 | HTTP_BAD_GATEWAY | 錯誤網關 | |
503 | Service | Unavailable | 服務器暫時無法處理請求,可能是超負荷或者維護等原因。 | HTTP_UNAVAILABLE | 服務不可用 |
Cookie和Cookie管理
一般在Servlet應用中,Cookie是識別當前用戶,實現持久會話的最佳方式。
從過期時間分類來看,Cookie分為會話Cookie和持久Cookie,會話Cookie的過期時間比較短,持久Cookie的過期時間比較長或者不會過期,Cookie的過期策略等控制應該由服務端控制。
由于Cookie是直接暴露在客戶端,一般不能使用Cookie存放敏感的數據,需要存放敏感數據可以考慮使用數據加密處理。
很多網站使用一些小文本串在連接之間存儲持久的客戶端狀態,這些小文本串稱為Cookie(中文翻譯為:小甜點)。
Cookie在請求和響應的首部從服務器傳到客戶端,再從客戶端傳回服務器,服務器使用Cookie來指示sessionID、購物車內容、登錄憑據等。
除了簡單的name=value對,Cookie可以有多個屬性來控制它們的作用域,包括過期日期、路徑、域、端口、版本和安全選項。
JDK中java.net.CookieStore類提供了對Cookie的增刪查操作,它的默認實現是java.net.InMemoryCookieStore,如果實現CookieStore,JDK中的Cookie默認是存放在內存中的。
另外,java.net.CookieManager內部持有CookiePolicy和CookieStore,定義了一系列管理Cookie的方法,一般通過CookieManager操作Cookie,當然也可以通過實現CookieStore,覆蓋默認的CookieManager來實現Cookie的自定義管理。