HTTP
HTTP(Hyper Text Transfer Protocol)
, 譯為超文本傳輸協(xié)議
-- 是互聯(lián)網(wǎng)中應(yīng)用最廣泛的應(yīng)用層協(xié)議之一
-- 設(shè)計HTTP
最初的目的是: 提供一種發(fā)布和接收HTML
頁面的方法, 由URI
來標(biāo)識具體的資源
-- 后面用HTTP
來傳遞的數(shù)據(jù)格式不僅僅是HTML
, 應(yīng)用非常廣泛HTML(Hyper Text Markup Language)
: 超文本標(biāo)記語言
-- 用以編寫網(wǎng)頁
版本
1991年, HTTP/0.9
-- 只支持GET
請求方法獲取文本數(shù)據(jù)(比如HTML
文檔), 且不支持請求頭, 響應(yīng)頭等, 無法向服務(wù)器傳遞太多信息1996年, HTTP/1.0
-- 支持POST
,HEAD
等請求方法, 支持請求頭, 響應(yīng)頭等, 支持更多種數(shù)據(jù)類型 (不再局限于文本數(shù)據(jù))
-- 瀏覽器的每次請求都需要與服務(wù)器建立一個TCP
連接, 請求處理完成后立即斷開TCP
連接1997年, HTTP/1.1
(最經(jīng)典, 使用最廣泛的版本)
-- 支持PUT
,DELETE
等請求辦法
-- 采用持久連接(Connection: keep-alive)
, 多個請求可以共用一個TCP
連接2015年, HTTP/2.0
2018年, HTTP/3.0
報文格式
ABNF (Augmented BNF)
-- 是BNF (Backus-Naur Form, 譯為: 巴科斯-瑙爾范式)
的修改, 增強版
-- 在RFC 52234
中表明:ABNF
用作internet
中通信協(xié)議的定義語言
--ABNF
是最嚴謹?shù)?code>HTTP報文格式描述形式, 脫離ABNF
談?wù)?code>HTTP報文格式, 往往都是片面, 不嚴謹?shù)?/p>關(guān)于
HTTP
報文格式的定義
--RFC 2616 4.HTTP Message(舊)
--RFC 7230 3.Message Format(新)
ABNF-核心規(guī)則
報文格式-request-line, status-line
request-line = method SP request-target SP HTTP-version CRLF
HTTP-version = HTTP-name "/" DIGIT"."DIGIT"
HTTP-name = %48.54.54.50;HTTP
GET /hello/ HTTP/1.1
status-line = HTTP-version SP status-code SP reason-phrase CRLF
status-code = 3DIGIT
reason-phrase = *(HTAB / SP / VCHAR / obs-text)
HTTP/1.1 200
HTTP/1.1 200 OK
報文格式 - header-filed, message-body
header-filed = filed-name ":" OWS field-value OWS
field-name = token
field-value = *(field-content / obs-fold)
OWS = *(SP / HTAB)
message-body = *OCTET
URL
的編碼
URL
中一旦出現(xiàn)了一些特殊字符(比如中文, 空格), 需要進行編碼
-- 在瀏覽器地址欄輸入URL
時, 是采用UTF-8
進行編碼比如
-- 編碼前:https://www.baidu.com/s?wd=百度
-- 編碼前:https://www.baidu.com/s?wd=%E5%8D%8E%E4%B8%BA
請求方法
GET
常用于讀取的操作, 請求參數(shù)直接拼接在URL
的后面(瀏覽器對URL
是有長度限制的)POST
常用于添加, 修改, 刪除的操作, 請求參數(shù)可以放到請求體中(沒有大小限制)**(URL也可以拼接參數(shù), 請求體里也拼接參數(shù))**
HEAD
請求得到的與GET
請求相同的響應(yīng), 但沒有響應(yīng)體
-- 使用場景舉例: 在下載一個大文件前, 先獲取其大小, 再決定是否要下載. 以此可以節(jié)約帶寬資源OPTIONS
用于獲取目的資源所支持的通信選項, 比如服務(wù)器支持的請求方法
--OPTIONS * HTTP/1.1
PUT
用于對已存在的資源進行整體覆蓋PATCH
用于對資源進行部分修改(資源不存在, 會創(chuàng)建新的資源)DELETE
用于刪除指定的資源TRACE
請求服務(wù)器回顯其收到的請求信息, 主要用于HTTP
請求的測試和診斷CONNECT
可以開啟一個客戶端與所請求資源之間的雙向溝通的通道, 它可以用來創(chuàng)建隧道(tunnel)
-- 可以用來訪問采用了SSL(HTTPS)
協(xié)議的站點
頭部字段(Header Field)
- 頭部字段可以分為
4
種類型
-- 請求頭字段(Request Header Fields)
?有關(guān)要獲取的資源或客戶端本身信息的消息頭
-- 響應(yīng)頭字段(ResponseHeader Fields)
?有關(guān)響應(yīng)的補充信息, 比如服務(wù)器本身(名稱和版本等)的消息頭
-- 實體頭字段(Entity Header Fields)
?有關(guān)實體主體的更多信息, 比如主體長度(Content-Length)
或MIME
類型
-- 請求頭字段(General Header Fields)
?同時適用于請求和響應(yīng)消息, 但與消息主體無關(guān)的消息頭
請求頭字段
響應(yīng)頭字段
狀態(tài)碼(Status Code)
在
RFC 2616 10.Status Code Definitions
規(guī)范中定義
-- 狀態(tài)碼指示HTTP
請求是否已成功完成狀態(tài)碼可以分為
5
類
-- 信息響應(yīng):100~199
-- 成功響應(yīng):200~299
-- 重定向:300~399
-- 客戶端錯誤:400~499
-- 服務(wù)器錯誤:500~599
100 Continue
-- 請求的初始部分已經(jīng)被服務(wù)器收到, 并且并沒有被服務(wù)器拒絕. 客戶端應(yīng)該繼續(xù)發(fā)送剩余的請求, 如果請求已經(jīng)完成, 就忽略這個響應(yīng)
-- 允許客戶端發(fā)送帶請求體的請求前, 判斷服務(wù)器是否愿意接手請求(服務(wù)器通過請求頭判斷)
-- 在某些情況下, 如果服務(wù)器在不看請求體就拒絕請求時, 客戶端就發(fā)送請求體是不恰當(dāng)或者低效的200 OK
請求成功302 Found
請求的資源被暫時移動到了由Location
頭部指定的URL
上304 Not Modified
說明無需再次傳輸請求內(nèi)容, 也就是說可以使用緩存內(nèi)容400 Bad Request
由于語法無效, 服務(wù)器無法理解該需求401 Unauthorized
由于缺乏目標(biāo)資源要求的身份驗證憑證403 Forbidden
服務(wù)器端有能力處理該請求, 但是拒絕授權(quán)訪問404 Not Found
服務(wù)器端無法找到所請求的資源405 Method Not Allowed
服務(wù)器禁止了使用當(dāng)前HTTP
方法的請求406 Not Acceptable
服務(wù)器端無法提供與Accept-Charset
以及Accept-Language
指定的值相匹配的響應(yīng)408 Request Timeout
服務(wù)器想要將沒有在使用的連接關(guān)閉
-- 一些服務(wù)器會在空閑連接上發(fā)送此信息, 即便是在客戶端沒有發(fā)送任何請求的情況下500 Internal Server Error
所請求的服務(wù)器遇到意外的情況并阻止其執(zhí)行請求501 Not Implemented
請求的方法不被服務(wù)器支持, 因此無法被處理(注意和405
的區(qū)別)
-- 服務(wù)器必須支持的方法(即不會返回這個狀態(tài)碼的方法)只有GET
和HEAD
502 Bad Gateway
作為網(wǎng)關(guān)或代理角色的服務(wù)器, 從上游服務(wù)器(如tomcat
)中接收到的響應(yīng)是無效的503 Service Unavailable
服務(wù)器尚未處于可以接受請求的狀態(tài)
-- 通常造成這種情況的原因是由于服務(wù)器停機維護或者已超載
form
提交-常用屬性
-
action
請求的URI
-
method
請求方法(GET, POST)
-
enctype
POST
請求時, 請求體的編碼方式
--application/x-www-form-urlencoded
(默認值)
?用&
分隔參數(shù), 用=
分隔鍵和值, 字符用URL
編碼方式進行編碼
-- multipart/form-data
?文件上傳時必須使用這種編碼方式
form
提交-multipart/form-data
- 參考
RFC 1521
- 請求頭
--Content-Type: multipart/form-data; boundary=xxx
image.png
同源策略
-
瀏覽器有個同源策略
(Same-Origin Policy)
-- 它規(guī)定了: 默認情況下,AJAX
請求只能發(fā)送給同源的URL
-- 同源是指3
個相同: 協(xié)議, 域名(IP)
, 端口
image.png img, script, link, iframe, video, audio
等標(biāo)簽不受同源策略的約束
跨域資源共享
解決
AJAX
跨域請求的常用方法
--CORS(Cross-Origin Resource Sharing)
跨域資源共享CORS
的實現(xiàn)需要客戶端和服務(wù)器同時支持
-- 客戶端
?所有的瀏覽器都支持(IE
至少是IE10
版本)
-- 服務(wù)器
?需要返回相應(yīng)的響應(yīng)頭(比如Access-Control-Allow-Origin
)
?告知瀏覽器這是一個允許跨域訪問的請求
后端在返回數(shù)據(jù)前就應(yīng)該先判斷origin和允許訪問的是否一致, 否則就算瀏覽器報錯跨域問題, 前端一樣可以拿到數(shù)據(jù), 后端的數(shù)據(jù)就存在不安全性
會話跟蹤
HTTP
是一種"無狀態(tài)"(stateless)
的協(xié)議
-- 每次客戶端訪問網(wǎng)頁時, 客戶端都會打開與Web
服務(wù)器的單獨連接
-- 并且服務(wù)器不會自動保留之前客戶端請求的任何記錄
-- 所以服務(wù)器無法識別多個請求是否來自同一個客戶端(比如瀏覽器)在很多應(yīng)用場景中, 都有以下需求
-- 服務(wù)器能夠識別出多個請求是夠來自同一個客戶端
-- 在來自同一個客戶端的多個請求之間共享數(shù)據(jù)以上需求可以使用會話跟蹤技術(shù)來完成. 在
Java
中, 實現(xiàn)會話跟蹤的常用方法是
--Cookie
--Session
Cookie & Session
Cookie
是直接存儲在瀏覽器本地的一小串?dāng)?shù)據(jù)
-- 使用document.cookie
訪問Cookie
-- 在修改Cookie
時, 只會修改其中提到的Cookie
--name=value
必須被編碼(encodeURIComponent)
-- 一個Cookie
最大為4kb
, 每個網(wǎng)站最多有20+
個左右的Cookie
(具體取決于瀏覽器)Windows
中Chrome
瀏覽器的Cookie
存放位置
--C:\Users\用戶名\AppData\Local\Google\Chrome\User Data\Default\Cookies
-- 使用SQLite
數(shù)據(jù)庫進行存儲
Cookie的有效期
如果沒有設(shè)置
Cookie
的過期時間, 則當(dāng)瀏覽器關(guān)閉時,Cookie
就失效了expries
-- 必須完全采用GMT
時區(qū)的格式, 可以受用date.toUTCString
來獲取
-- 例如:expires=Tue, 19 Jan 2038 03:14:07 GMT
max-age
-- 過期時間距離當(dāng)前時間的秒數(shù)
-- 例如:max-age=60
Cookie
(只歸一個瀏覽器管)
-- 在客戶端(瀏覽器)存儲一些數(shù)據(jù), 存儲到本地磁盤(硬盤)
-- 服務(wù)器可以返回Cookie
交給客戶端去存儲Session
(針對用戶瀏覽器的,會話跟蹤
)
-- 在服務(wù)器存儲一些數(shù)據(jù), 存儲到內(nèi)存中
Cookie
的作用域
domain
和path
標(biāo)識定義了Cookie
的作用域, 即Cookie
應(yīng)該發(fā)送給哪些URL
domain
-- 標(biāo)識指定了哪些主機可以接受Cookie
-- 如果不指定, 默認為當(dāng)前文檔的主機(不包含子域名); 如果指定了domain
, 則一般包含子域名
-- 例如: 如果設(shè)置domain=520it.com
, 則Cookie
也包含在子域名中(如bbs.520it.com
)path
-- 標(biāo)識指定了主機下的哪些路徑可以接受Cookie
, 子路徑也會被匹配
-- 例如:設(shè)置path=/docs
, 則以下地址都會匹配
??/docs
??/docs/one/
??/docs/one/img
服務(wù)器設(shè)置Cookie
Cookie
通常是由Web
服務(wù)器使用響應(yīng)頭Set-Cookie
設(shè)置的關(guān)于
max-age
-在
JavaScript
中, 如果設(shè)置為0或者負數(shù), 會立即刪除Cookie
-- 在Java
中: 如果設(shè)置為0
, 是立即刪除Cookie
; 如果設(shè)置為負數(shù), 按默認情況處理
getSession
內(nèi)部的原理
- 檢查客戶端是否有發(fā)送一個叫做
JSESSIONID
的Cookie
-- 如果沒有
??創(chuàng)建一個新的Session
對象, 并且這個Session
對象會有一個id
??這個Session
對象會保留在服務(wù)器的內(nèi)存中
??在響應(yīng)的時候, 會添加一個Cookie(JSESSIONID=Session對象的id)
給客戶端
-- 如果有
??返回id
為JSESSIONID
的Session
對象
JSESSIONID
默認情況下, 當(dāng)用戶關(guān)閉瀏覽器時,
Cookie
中存儲的JSESSIONID
就會被銷毀可以通過以下代碼延長
JSESSIONID
在客戶端的壽命
Cookie cookie = new Cookie("JSESSIONID", request.getSession().getId());
cookie.setMaxAge(3600);
response.addCookie(cookie);
Session
的有效期
-
Session
的有效期默認是30
分鐘 - 可以在
web.xml
中配置失效時間(單位是分鐘)
<session-config>
<session-timeout>30</session-timeout>
</session-config>
總結(jié)
Cookie
-- 數(shù)據(jù)存儲在瀏覽器客戶端
-- 數(shù)據(jù)有大小和數(shù)量的限制
-- 適合存儲一些小型, 不敏感的數(shù)據(jù)
-- 默認情況下, 關(guān)閉瀏覽器后就會銷毀Session
-- 數(shù)據(jù)存儲在服務(wù)器端
-- 數(shù)據(jù)沒有大小和數(shù)量的限制
-- 可以存儲大型, 敏感的數(shù)據(jù)(比如用戶信息)
-- 默認情況下, 未使用30
分鐘后就會銷毀