Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
注于Java領域優質技術,歡迎關注
作者:滌生_Woo
本篇文章篇幅比較長,先來個思維導圖預覽一下。
一張圖帶你看完本篇文章
1.計算機網絡體系結構分層
計算機網絡體系結構分層
2.TCP/IP 通信傳輸流
利用 TCP/IP 協議族進行網絡通信時,會通過分層順序與對方進行通信。發送端從應用層往下走,接收端則從鏈路層往上走。如下:
TCP/IP 通信傳輸流
如下圖所示:
HTTP 請求
在網絡體系結構中,包含了眾多的網絡協議,這篇文章主要圍繞 HTTP 協議(HTTP/1.1版本)展開。
HTTP協議(HyperText Transfer Protocol,超文本傳輸協議)是用于從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議。它可以使瀏覽器更加高效,使網絡傳輸減少。它不僅保證計算機正確快速地傳輸超文本文檔,還確定傳輸文檔中的哪一部分,以及哪部分內容首先顯示(如文本先于圖形)等。 HTTP是客戶端瀏覽器或其他程序與Web服務器之間的應用層通信協議。在Internet上的Web服務器上存放的都是超文本信息,客戶機需要通過HTTP協議傳輸所要訪問的超文本信息。HTTP包含命令和傳輸信息,不僅可用于Web訪問,也可以用于其他因特網/內聯網應用系統之間的通信,從而實現各類應用資源超媒體訪問的集成。 我們在瀏覽器的地址欄里輸入的網站地址叫做URL (Uniform Resource Locator,統一資源定位符)。就像每家每戶都有一個門牌地址一樣,每個網頁也都有一個Internet地址。當你在瀏覽器的地址框中輸入一個URL或是單擊一個超級鏈接時,URL就確定了要瀏覽的地址。瀏覽器通過超文本傳輸協議(HTTP),將Web服務器上站點的網頁代碼提取出來,并翻譯成漂亮的網頁。
HTTP請求響應模型
HTTP通信機制是在一次完整的 HTTP 通信過程中,客戶端與服務器之間將完成下列7個步驟:
1 建立 TCP 連接
在HTTP工作開始之前,客戶端首先要通過網絡與服務器建立連接,該連接是通過 TCP 來完成的,該協議與 IP 協議共同構建 Internet,即著名的 TCP/IP 協議族,因此 Internet 又被稱作是 TCP/IP 網絡。HTTP 是比 TCP 更高層次的應用層協議,根據規則,只有低層協議建立之后,才能進行高層協議的連接,因此,首先要建立 TCP 連接,一般 TCP 連接的端口號是80;
2 客戶端向服務器發送請求命令
一旦建立了TCP連接,客戶端就會向服務器發送請求命令;
例如:GET/sample/hello.jsp HTTP/1.1
3 客戶端發送請求頭信息
客戶端發送其請求命令之后,還要以頭信息的形式向服務器發送一些別的信息,之后客戶端發送了一空白行來通知服務器,它已經結束了該頭信息的發送;
4 服務器應答
客戶端向服務器發出請求后,服務器會客戶端返回響應;
例如: HTTP/1.1 200 OK
響應的第一部分是協議的版本號和響應狀態碼
5 服務器返回響應頭信息
正如客戶端會隨同請求發送關于自身的信息一樣,服務器也會隨同響應向用戶發送關于它自己的數據及被請求的文檔;
6 服務器向客戶端發送數據
服務器向客戶端發送頭信息后,它會發送一個空白行來表示頭信息的發送到此為結束,接著,它就以 Content-Type 響應頭信息所描述的格式發送用戶所請求的實際數據;
7 服務器關閉 TCP 連接
一般情況下,一旦服務器向客戶端返回了請求數據,它就要關閉 TCP 連接,然后如果客戶端或者服務器在其頭信息加入了這行代碼 Connection:keep-alive ,TCP 連接在發送后將仍然保持打開狀態,于是,客戶端可以繼續通過相同的連接發送請求。保持連接節省了為每個請求建立新連接所需的時間,還節約了網絡帶寬。
1.通過請求和響應的交換達成通信
應用 HTTP 協議時,必定是一端擔任客戶端角色,另一端擔任服務器端角色。僅從一條通信線路來說,服務器端和客服端的角色是確定的。HTTP 協議規定,請求從客戶端發出,最后服務器端響應該請求并返回。換句話說,肯定是先從客戶端開始建立通信的,服務器端在沒有接收到請求之前不會發送響應。
2.HTTP 是不保存狀態的協議
HTTP 是一種無狀態協議。協議自身不對請求和響應之間的通信狀態進行保存。也就是說在 HTTP 這個級別,協議對于發送過的請求或響應都不做持久化處理。這是為了更快地處理大量事務,確保協議的可伸縮性,而特意把 HTTP 協議設計成如此簡單的。
可是隨著 Web 的不斷發展,我們的很多業務都需要對通信狀態進行保存。于是我們引入了 Cookie 技術。有了 Cookie 再用 HTTP 協議通信,就可以管理狀態了。
3.使用 Cookie 的狀態管理
Cookie 技術通過在請求和響應報文中寫入 Cookie 信息來控制客戶端的狀態。Cookie 會根據從服務器端發送的響應報文內的一個叫做 Set-Cookie 的首部字段信息,通知客戶端保存Cookie。當下次客戶端再往該服務器發送請求時,客戶端會自動在請求報文中加入 Cookie 值后發送出去。服務器端發現客戶端發送過來的 Cookie 后,會去檢查究竟是從哪一個客戶端發來的連接請求,然后對比服務器上的記錄,最后得到之前的狀態信息。
Cookie 的流程
4.請求 URI 定位資源
HTTP 協議使用 URI 定位互聯網上的資源。正是因為 URI 的特定功能,在互聯網上任意位置的資源都能訪問到。
5.告知服務器意圖的 HTTP 方法(HTTP/1.1)
HTTP 方法
6.持久連接
HTTP 協議的初始版本中,每進行一個 HTTP 通信都要斷開一次 TCP 連接。比如使用瀏覽器瀏覽一個包含多張圖片的 HTML 頁面時,在發送請求訪問 HTML 頁面資源的同時,也會請求該 HTML 頁面里包含的其他資源。因此,每次的請求都會造成無畏的 TCP 連接建立和斷開,增加通信量的開銷。
為了解決上述 TCP 連接的問題,HTTP/1.1 和部分 HTTP/1.0 想出了持久連接的方法。其特點是,只要任意一端沒有明確提出斷開連接,則保持 TCP 連接狀態。旨在建立一次 TCP 連接后進行多次請求和響應的交互。在 HTTP/1.1 中,所有的連接默認都是持久連接。
7.管線化
持久連接使得多數請求以管線化方式發送成為可能。以前發送請求后需等待并接收到響應,才能發送下一個請求。管線化技術出現后,不用等待亦可發送下一個請求。這樣就能做到同時并行發送多個請求,而不需要一個接一個地等待響應了。
比如,當請求一個包含多張圖片的 HTML 頁面時,與挨個連接相比,用持久連接可以讓請求更快結束。而管線化技術要比持久連接速度更快。請求數越多,時間差就越明顯。
1.HTTP 報文
用于 HTTP 協議交互的信息被稱為 HTTP 報文。請求端(客戶端)的 HTTP 報文叫做請求報文;響應端(服務器端)的叫做響應報文。HTTP 報文本身是由多行(用 CR+LF 作換行符)數據構成的字符串文本。
2.HTTP 報文結構
HTTP 報文大致可分為報文首部和報文主體兩部分。兩者由最初出現的空行(CR+LF)來劃分。通常,并不一定有報文主體。如下:
HTTP 報文結構
2.1請求報文結構
請求報文結構
請求報文的首部內容由以下數據組成:
請求報文的示例,如下:
請求報文示例
2.2響應報文結構
響應報文結構
響應報文的首部內容由以下數據組成:
響應報文的示例,如下:
響應報文示例
1.請求行
舉個栗子,下面是一個 HTTP 請求的報文:
GET /index.htm HTTP/1.1 Host: sample.com
其中,下面的這行就是請求行,
GET /index.htm HTTP/1.1
綜合來看,大意是請求訪問某臺 HTTP 服務器上的 /index.htm 頁面資源。
2.狀態行
同樣舉個栗子,下面是一個 HTTP 響應的報文:
HTTP/1.1 200 OK Date: Mon, 10 Jul 2017 15:50:06 GMT Content-Length: 256 Content-Type: text/html <html> ...
其中,下面的這行就是狀態行,
HTTP/1.1 200 OK
1.首部字段概述
先來回顧一下首部字段在報文的位置,HTTP 報文包含報文首部和報文主體,報文首部包含請求行(或狀態行)和首部字段。
在報文眾多的字段當中,HTTP 首部字段包含的信息最為豐富。首部字段同時存在于請求和響應報文內,并涵蓋 HTTP 報文相關的內容信息。使用首部字段是為了給客服端和服務器端提供報文主體大小、所使用的語言、認證信息等內容。
2.首部字段結構
3.首部字段類型
首部字段根據實際用途被分為以下4種類型:
4.通用首部字段(HTTP/1.1)
4.1 Cache-Control
通過指定首部字段 Cache-Control 的指令,就能操作緩存的工作機制。
4.1.1 可用的指令一覽
可用的指令按請求和響應分類如下:
緩存請求指令
緩存響應指令
4.1.2 表示能否緩存的指令
public 指令
Cache-Control: public
當指定使用 public 指令時,則明確表明其他用戶也可利用緩存。
private 指令
Cache-Control: private
當指定 private 指令后,響應只以特定的用戶作為對象,這與 public 指令的行為相反。緩存服務器會對該特定用戶提供資源緩存的服務,對于其他用戶發送過來的請求,代理服務器則不會返回緩存。
no-cache 指令
Cache-Control: no-cache
Cache-Control: no-cache=Location
由服務器返回的響應中,若報文首部字段 Cache-Control 中對 no-cache 字段名具體指定參數值,那么客戶端在接收到這個被指定參數值的首部字段對應的響應報文后,就不能使用緩存。換言之,無參數值的首部字段可以使用緩存。只能在響應指令中指定該參數。
no-store 指令
Cache-Control: no-store
當使用 no-store 指令時,暗示請求(和對應的響應)或響應中包含機密信息。因此,該指令規定緩存不能在本地存儲請求或響應的任一部分。
注意:no-cache 指令代表不緩存過期的指令,緩存會向源服務器進行有效期確認后處理資源;no-store 指令才是真正的不進行緩存。
4.1.3 指定緩存期限和認證的指令
s-maxage 指令
Cache-Control: s-maxage=604800(單位:秒)
max-age 指令
Cache-Control: max-age=604800(單位:秒)
min-fresh 指令
Cache-Control: min-fresh=60(單位:秒)
min-fresh 指令要求緩存服務器返回至少還未過指定時間的緩存資源。
max-stale 指令
Cache-Control: max-stale=3600(單位:秒)
only-if-cached 指令
Cache-Control: only-if-cached
表示客戶端僅在緩存服務器本地緩存目標資源的情況下才會要求其返回。換言之,該指令要求緩存服務器不重新加載響應,也不會再次確認資源的有效性。
must-revalidate 指令
Cache-Control: must-revalidate
使用 must-revalidate 指令,代理會向源服務器再次驗證即將返回的響應緩存目前是否仍有效。另外,使用 must-revalidate 指令會忽略請求的 max-stale 指令。
proxy-revalidate 指令
Cache-Control: proxy-revalidate
proxy-revalidate 指令要求所有的緩存服務器在接收到客戶端帶有該指令的請求返回響應之前,必須再次驗證緩存的有效性。
no-transform 指令
Cache-Control: no-transform
使用 no-transform 指令規定無論是在請求還是響應中,緩存都不能改變實體主體的媒體類型。這樣做可防止緩存或代理壓縮圖片等類似操作。
4.1.4 Cache-Control 擴展
Cache-Control: private, community="UCI"
通過 cache-extension 標記(token),可以擴展 Cache-Control 首部字段內的指令。上述 community 指令即擴展的指令,如果緩存服務器不能理解這個新指令,就會直接忽略掉。
4.2 Connection
Connection 首部字段具備以下兩個作用:
控制不再轉發的首部字段
Connection: Upgrade
在客戶端發送請求和服務器返回響應中,使用 Connection 首部字段,可控制不再轉發給代理的首部字段,即刪除后再轉發(即Hop-by-hop首部)。
管理持久連接
Connection: close
HTTP/1.1 版本的默認連接都是持久連接。當服務器端想明確斷開連接時,則指定 Connection 首部字段的值為 close。
Connection: Keep-Alive
HTTP/1.1 之前的 HTTP 版本的默認連接都是非持久連接。為此,如果想在舊版本的 HTTP 協議上維持持續連接,則需要指定 Connection 首部字段的值為 Keep-Alive。
4.3 Date
表明創建 HTTP 報文的日期和時間。
Date: Mon, 10 Jul 2017 15:50:06 GMT
HTTP/1.1 協議使用在 RFC1123 中規定的日期時間的格式。
4.4 Pragma
Pragma 首部字段是 HTTP/1.1 版本之前的歷史遺留字段,僅作為與 HTTP/1.0 的向后兼容而定義。
Pragma: no-cache
Cache-Control: no-cache Pragma: no-cache
4.5 Trailer
Trailer: Expires
首部字段 Trailer 會事先說明在報文主體后記錄了哪些首部字段。可應用在 HTTP/1.1 版本分塊傳輸編碼時。
4.6 Transfer-Encoding
Transfer-Encoding: chunked
4.7 Upgrade
Upgrade: TSL/1.0
用于檢測 HTTP 協議及其他協議是否可使用更高的版本進行通信,其參數值可以用來指定一個完全不同的通信協議。
4.8 Via
Via: 1.1 a1.sample.com(Squid/2.7)
4.9 Warning
該首部字段通常會告知用戶一些與緩存相關的問題的警告。
Warning 首部字段的格式如下:
Warning:[警告碼][警告的主機:端口號] "[警告內容]"([日期時間])
最后的日期時間可省略。
HTTP/1.1 中定義了7種警告,警告碼對應的警告內容僅推薦參考,另外,警告碼具備擴展性,今后有可能追加新的警告碼。
5. 請求首部字段(HTTP/1.1)
5.1 Accept
Accept: text/html, application/xhtml+xml, application/xml; q=0.5
5.2 Accept-Charset
Accept-Charset: iso-8859-5, unicode-1-1; q=0.8
Accept-Charset 首部字段可用來通知服務器用戶代理支持的字符集及字符集的相對優先順序。另外,可一次性指定多種字符集。同樣使用 q=[數值] 來表示相對優先級。
5.3 Accept-Encoding
Accept-Encoding: gzip, deflate
Accept-Encoding 首部字段用來告知服務器用戶代理支持的內容編碼及內容編碼的優先順序,并可一次性指定多種內容編碼。同樣使用 q=[數值] 來表示相對優先級。也可使用星號(*)作為通配符,指定任意的編碼格式。
5.4 Accept-Language
Accept-Lanuage: zh-cn,zh;q=0.7,en=us,en;q=0.3
告知服務器用戶代理能夠處理的自然語言集(指中文或英文等),以及自然語言集的相對優先級,可一次性指定多種自然語言集。同樣使用 q=[數值] 來表示相對優先級。
5.5 Authorization
Authorization: Basic ldfKDHKfkDdasSAEdasd==
告知服務器用戶代理的認證信息(證書值)。通常,想要通過服務器認證的用戶代理會在接收到返回的 401 狀態碼響應后,把首部字段 Authorization 加入請求中。共用緩存在接收到含有 Authorization 首部字段的請求時的操作處理會略有差異。
5.6 Expect
Expect: 100-continue
告知服務器客戶端期望出現的某種特定行為。
5.7 From
From: Deeson_Woo@163.com
告知服務器使用用戶代理的電子郵件地址。
5.8 Host
Host: www.jianshu.com
5.9 If-Match
形如 If-xxx 這種樣式的請求首部字段,都可稱為條件請求。服務器接收到附帶條件的請求后,只有判斷指定條件為真時,才會執行請求。
If-Match: "123456"
5.10 If-Modified-Since
If-Modified-Since: Mon, 10 Jul 2017 15:50:06 GMT
5.11 If-None-Match
If-None-Match: "123456"
首部字段 If-None-Match 屬于附帶條件之一。它和首部字段 If-Match 作用相反。用于指定 If-None-Match 字段值的實體標記(ETag)值與請求資源的 ETag 不一致時,它就告知服務器處理該請求。
5.12 If-Range
If-Range: "123456"
5.13 If-Unmodified-Since
If-Unmodified-Since: Mon, 10 Jul 2017 15:50:06 GMT
首部字段 If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服務器,指定的請求資源只有在字段值內指定的日期時間之后,未發生更新的情況下,才能處理請求。如果在指定日期時間后發生了更新,則以狀態碼 412 Precondition Failed 作為響應返回。
5.14 Max-Forwards
Max-Forwards: 10
通過 TRACE 方法或 OPTIONS 方法,發送包含首部字段 Max-Forwards 的請求時,該字段以十進制整數形式指定可經過的服務器最大數目。服務器在往下一個服務器轉發請求之前,Max-Forwards 的值減 1 后重新賦值。當服務器接收到 Max-Forwards 值為 0 的請求時,則不再進行轉發,而是直接返回響應。
5.15 Proxy-Authorization
Proxy-Authorization: Basic dGlwOjkpNLAGfFY5
5.16 Range
Range: bytes=5001-10000
5.17 Referer
Referer: http://www.sample.com/index.html
首部字段 Referer 會告知服務器請求的原始資源的 URI。
5.18 TE
TE: gzip, deflate; q=0.5
5.19 User-Agent
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101
6.1 Accept-Ranges
Accept-Ranges: bytes
6.2 Age
Age: 1200
6.3 ETag
ETag: "usagi-1234"
6.4 Location
Location: http://www.sample.com/sample.html
6.5 Proxy-Authenticate
Proxy-Authenticate: Basic realm="Usagidesign Auth"
6.6 Retry-After
Retry-After: 180
6.7 Server
Server: Apache/2.2.6 (Unix) PHP/5.2.5
首部字段 Server 告知客戶端當前服務器上安裝的 HTTP 服務器應用程序的信息。不單單會標出服務器上的軟件應用名稱,還有可能包括版本號和安裝時啟用的可選項。
6.8 Vary
Vary: Accept-Language
6.9 WWW-Authenticate
WWW-Authenticate: Basic realm="Usagidesign Auth"
首部字段 WWW-Authenticate 用于 HTTP 訪問認證。它會告知客戶端適用于訪問請求 URI 所指定資源的認證方案(Basic 或是 Digest)和帶參數提示的質詢(challenge)。
7. 實體首部字段(HTTP/1.1)
7.1 Allow
Allow: GET, HEAD
7.2 Content-Encoding
Content-Encoding: gzip
7.3 Content-Language
Content-Language: zh-CN
首部字段 Content-Language 會告知客戶端,實體主體使用的自然語言(指中文或英文等語言)。
7.4 Content-Length
Content-Length: 15000
首部字段 Content-Length 表明了實體主體部分的大小(單位是字節)。對實體主體進行內容編碼傳輸時,不能再使用 Content-Length首部字段。
7.5 Content-Location
Content-Location: http://www.sample.com/index.html
首部字段 Content-Location 給出與報文主體部分相對應的 URI。和首部字段 Location 不同,Content-Location 表示的是報文主體返回資源對應的 URI。
7.6 Content-MD5
Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==
首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于檢查報文主體在傳輸過程中是否保持完整,以及確認傳輸到達。
7.7 Content-Range
Content-Range: bytes 5001-10000/10000
針對范圍請求,返回響應時使用的首部字段 Content-Range,能告知客戶端作為響應返回的實體的哪個部分符合范圍請求。字段值以字節為單位,表示當前發送部分及整個實體大小。
7.8 Content-Type
Content-Type: text/html; charset=UTF-8
首部字段 Content-Type 說明了實體主體內對象的媒體類型。和首部字段 Accept 一樣,字段值用 type/subtype 形式賦值。參數 charset 使用 iso-8859-1 或 euc-jp 等字符集進行賦值。
7.9 Expires
Expires: Mon, 10 Jul 2017 15:50:06 GMT
7.10 Last-Modified
Last-Modified: Mon, 10 Jul 2017 15:50:06 GMT
首部字段 Last-Modified 指明資源最終修改的時間。一般來說,這個值就是 Request-URI 指定資源被修改的時間。但類似使用 CGI 腳本進行動態數據處理時,該值有可能會變成數據最終修改時的時間。
8. 為 Cookie 服務的首部字段
8.1 Set-Cookie
Set-Cookie: status=enable; expires=Mon, 10 Jul 2017 15:50:06 GMT; path=/;
下面的表格列舉了 Set-Cookie 的字段值。
8.1.1 expires 屬性
8.1.2 path 屬性
Cookie 的 path 屬性可用于限制指定 Cookie 的發送范圍的文件目錄。
8.1.3 domain 屬性
8.1.4 secure 屬性
Cookie 的 secure 屬性用于限制 Web 頁面僅在 HTTPS 安全連接時,才可以發送 Cookie。
8.1.5 HttpOnly 屬性
8.2 Cookie
Cookie: status=enable
首部字段 Cookie 會告知服務器,當客戶端想獲得 HTTP 狀態管理支持時,就會在請求中包含從服務器接收到的 Cookie。接收到多個 Cookie 時,同樣可以以多個 Cookie 形式發送。
9. 其他首部字段
HTTP 首部字段是可以自行擴展的。所以在 Web 服務器和瀏覽器的應用上,會出現各種非標準的首部字段。
以下是最為常用的首部字段。
9.1 X-Frame-Options
X-Frame-Options: DENY
首部字段 X-Frame-Options 屬于 HTTP 響應首部,用于控制網站內容在其他 Web 網站的 Frame 標簽內的顯示問題。其主要目的是為了防止點擊劫持(clickjacking)攻擊。首部字段 X-Frame-Options 有以下兩個可指定的字段值:
9.2 X-XSS-Protection
X-XSS-Protection: 1
首部字段 X-XSS-Protection 屬于 HTTP 響應首部,它是針對跨站腳本攻擊(XSS)的一種對策,用于控制瀏覽器 XSS 防護機制的開關。首部字段 X-XSS-Protection 可指定的字段值如下:
9.3 DNT
DNT: 1
首部字段 DNT 屬于 HTTP 請求首部,其中 DNT 是 Do Not Track 的簡稱,意為拒絕個人信息被收集,是表示拒絕被精準廣告追蹤的一種方法。首部字段 DNT 可指定的字段值如下:
由于首部字段 DNT 的功能具備有效性,所以 Web 服務器需要對 DNT做對應的支持。
9.4 P3P
P3P: CP="CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND
首部字段 P3P 屬于 HTTP 響應首部,通過利用 P3P(The Platform for Privacy Preferences,在線隱私偏好平臺)技術,可以讓 Web 網站上的個人隱私變成一種僅供程序可理解的形式,以達到保護用戶隱私的目的。
要進行 P3P 的設定,需按以下操作步驟進行:
1. 狀態碼概述
2. 狀態碼類別
我們可以自行改變 RFC2616 中定義的狀態碼或者服務器端自行創建狀態碼,只要遵守狀態碼的類別定義就可以了。
3. 常用狀態碼解析
HTTP 狀態碼種類繁多,數量達幾十種。其中最常用的有以下 14 種,一起來看看。
3.1 200 OK
表示從客戶端發來的請求在服務器端被正常處理了。
3.2 204 No Content
3.3 206 Partial Content
表示客戶端進行了范圍請求,而服務器成功執行了這部分的 GET 請求。響應報文中包含由 Content-Range 首部字段指定范圍的實體內容。
3.4 301 Moved Permanently
永久性重定向。表示請求的資源已被分配了新的 URI。以后應使用資源現在所指的 URI。也就是說,如果已經把資源對應的 URI 保存為書簽了,這時應該按 Location 首部字段提示的 URI 重新保存。
3.5 302 Found
3.6 303 See Other
3.7 304 Not Modified
3.8 307 Temporary Redirect
臨時重定向。該狀態碼與 302 Found 有著相同的含義。
3.9 400 Bad Request
3.10 401 Unauthorized
3.11 403 Forbidden
表明對請求資源的訪問被服務器拒絕了。服務器端沒有必要給出詳細的拒絕理由,當然也可以在響應報文的實體主體部分對原因進行描述。
3.12 404 Not Found
表明服務器上無法找到請求的資源。除此之外,也可以在服務器端拒絕請求且不想說明理由的時候使用。
3.13 500 Internal Server Error
表明服務器端在執行請求時發生了錯誤。也可能是 Web 應用存在的 bug 或某些臨時的故障。
3.14 503 Service Unavailable
表明服務器暫時處于超負載或正在進行停機維護,現在無法處理請求。如果事先得知解除以上狀況需要的時間,最好寫入 Retry-After 首部字段再返回給客戶端。
1. HTTP 報文實體概述
HTTP 報文結構
大家請仔細看看上面示例中,各個組成部分對應的內容。
接著,我們來看看報文和實體的概念。如果把 HTTP 報文想象成因特網貨運系統中的箱子,那么 HTTP 實體就是報文中實際的貨物。
我們可以看到,上面示例右圖中深紅色框的內容就是報文的實體部分,而藍色框的兩部分內容分別就是實體首部和實體主體。而左圖中粉紅框內容就是報文主體。
通常,報文主體等于實體主體。只有當傳輸中進行編碼操作時,實體主體的內容發生變化,才導致它和報文主體產生差異。
2. 內容編碼
內容編碼類型:
3. 傳輸編碼
內容編碼是對報文的主體進行的可逆變換,是和內容的具體格式細節緊密相關的。
傳輸編碼也是作用在實體主體上的可逆變換,但使用它們是由于架構方面的原因,同內容的格式無關。使用傳輸編碼是為了改變報文中的數據在網絡上傳輸的方式。
內容編碼和傳輸編碼的對比
4. 分塊編碼
分塊編碼把報文分割成若干已知大小的塊。塊之間是緊挨著發送的,這樣就不需要在發送之前知道整個報文的大小了。分塊編碼是一種傳輸編碼,是報文的屬性。
分塊編碼與持久連接
若客戶端與服務器端之間不是持久連接,客戶端就不需要知道它在讀取的主體的長度,而只需要讀取到服務器關閉主體連接為止。
當使用持久連接時,在服務器寫主體之前,必須知道它的大小并在 Content-Length 首部中發送。如果服務器動態創建內容,就可能在發送之前無法知道主體的長度。
分塊編碼為這種困難提供了解決方案,只要允許服務器把主體分塊發送,說明每塊的大小就可以了。因為主體是動態創建的,服務器可以緩沖它的一部分,發送其大小和相應的塊,然后在主體發送完之前重復這個過程。服務器可以用大小為 0 的塊作為主體結束的信號,這樣就可以繼續保持連接,為下一個響應做準備。
來看看一個分塊編碼的報文示例:
分塊編碼的報文
5.多部分媒體類型
MIME 中的 multipart(多部分)電子郵件報文中包含多個報文,它們合在一起作為單一的復雜報文發送。每一部分都是獨立的,有各自的描述其內容的集,不同部分之間用分界字符串連接在一起。
相應得,HTTP 協議中也采納了多部分對象集合,發送的一份報文主體內可包含多種類型實體。
多部分對象集合包含的對象如下:
6. 范圍請求
假設你正在下載一個很大的文件,已經下了四分之三,忽然網絡中斷了,那下載就必須重頭再來一遍。為了解決這個問題,需要一種可恢復的機制,即能從之前下載中斷處恢復下載。要實現該功能,這就要用到范圍請求。
有了范圍請求, HTTP 客戶端可以通過請求曾獲取失敗的實體的一個范圍(或者說一部分),來恢復下載該實體。當然這有一個前提,那就是從客戶端上一次請求該實體到這一次發出范圍請求的時間段內,該對象沒有改變過。例如:
GET /bigfile.html HTTP/1.1 Host: www.sample.com Range: bytes=20224- ···
實體范圍請求示例
上面示例中,客戶端請求的是文檔開頭20224字節之后的部分。
HTTP 通信時,除客戶端和服務器外,還有一些用于協助通信的應用程序。如下列出比較重要的幾個:代理、緩存、網關、隧道、Agent 代理。
1.代理
代理
HTTP 代理服務器是 Web 安全、應用集成以及性能優化的重要組成模塊。代理位于客戶端和服務器端之間,接收客戶端所有的 HTTP 請求,并將這些請求轉發給服務器(可能會對請求進行修改之后再進行轉發)。對用戶來說,這些應用程序就是一個代理,代表用戶訪問服務器。
出于安全考慮,通常會將代理作為轉發所有 Web 流量的可信任中間節點使用。代理還可以對請求和響應進行過濾,安全上網或綠色上網。
2. 緩存
瀏覽器第一次請求:
瀏覽器第一次請求
瀏覽器再次請求:
瀏覽器再次請求
Web 緩存或代理緩存是一種特殊的 HTTP 代理服務器,可以將經過代理傳輸的常用文檔復制保存起來。下一個請求同一文檔的客戶端就可以享受緩存的私有副本所提供的服務了。客戶端從附近的緩存下載文檔會比從遠程 Web 服務器下載快得多。
3. 網關
HTTP / FTP 網關
網關是一種特殊的服務器,作為其他服務器的中間實體使用。通常用于將 HTTP 流量轉換成其他的協議。網關接收請求時就好像自己是資源的源服務器一樣。客戶端可能并不知道自己正在跟一個網關進行通信。
4. 隧道
HTTP/SSL 隧道
隧道是會在建立起來之后,就會在兩條連接之間對原始數據進行盲轉發的 HTTP 應用程序。HTTP 隧道通常用來在一條或多條 HTTP 連接上轉發非 HTTP 數據,轉發時不會窺探數據。
HTTP 隧道的一種常見用途就是通過 HTTP 連接承載加密的安全套接字層(SSL)流量,這樣 SSL 流量就可以穿過只允許 Web 流量通過的防火墻了。
5. Agent 代理
自動搜索引擎“網絡蜘蛛”
Agent 代理是代表用戶發起 HTTP 請求的客戶端應用程序。所有發布 Web 請求的應用程序都是 HTTP Agent 代理。
來源:簡書 鏈接:https://www.jianshu.com/p/6e9e4156ece3
今日內容:
1. Servlet
2. HTTP協議
3. Request
一、Servlet補充內容:
1.1 Servlet的體系結構:
Servlet -- 接口
|
GenericServlet -- 抽象類
|
HttpServlet -- 抽象類
1.2 GenericServlet:將Servlet接口中其他的方法做了默認空實現,只將service()方法作為抽象,將來定義Servlet類時,可以繼承GenericServlet,實現service()方法即可
1.3 HttpServlet:對http協議的一種封裝,簡化操作
1. 定義類繼承HttpServlet
2. 復寫doGet/doPost方法
1.2 Servlet相關配置
1.2.1 urlpartten:Servlet訪問路徑
1. 一個Servlet可以定義多個訪問路徑 : @WebServlet({"/d4","/dd4","/ddd4"})
2. 路徑定義規則:
1. /xxx:路徑匹配
2. /xxx/xxx:多層路徑,目錄結構
3. *.do:擴展名匹配
二、HTTP:
2.1 概念:Hyper Text Transfer Protocol 超文本傳輸協議
* 傳輸協議:定義了,客戶端和服務器端通信時,發送數據的格式
* 特點:
1. 基于TCP/IP的高級協議
2. 默認端口號:80
3. 基于請求/響應模型的:一次請求對應一次響應
4. 無狀態的:每次請求之間相互獨立,不能交互數據
* 歷史版本:
* 1.0:每一次請求響應都會建立新的連接
* 1.1:復用連接
2.2 請求消息數據格式
2.2.1 請求行:
請求方式 請求url 請求協議/版本
GET /login.html HTTP/1.1
2.2.2 請求方式:
* HTTP協議有7中請求方式,常用的有2種
* GET:
1. 請求參數在請求行中,在url后。
2. 請求的url長度有限制的
3. 不太安全
* POST:
1. 請求參數在請求體中
2. 請求的url長度沒有限制的
3. 相對安全
2.2.3 請求頭:客戶端瀏覽器告訴服務器一些信息
請求頭名稱: 請求頭值
* 常見的請求頭:
1. User-Agent:瀏覽器告訴服務器,我訪問你使用的瀏覽器版本信息
* 可以在服務器端獲取該頭的信息,解決瀏覽器的兼容性問題
2. Referer:http://localhost/login.html
* 告訴服務器,我(當前請求)從哪里來?
* 作用:
1. 防盜鏈:
2. 統計工作:
2.2.4 請求空行
空行,就是用于分割POST請求的請求頭,和請求體的。
2.2.5 請求體(正文):
* 封裝POST請求消息的請求參數的
2.2.6 請求消息舉例:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
username=zhangsan
三、Request:
3.1 request對象和response對象的原理
1. request和response對象是由服務器創建的。我們來使用它們
2. request對象是來獲取請求消息,response對象是來設置響應消息
3.2 request對象繼承體系結構:
ServletRequest -- 接口
| 繼承
HttpServletRequest -- 接口
| 實現
org.apache.catalina.connector.RequestFacade 類(tomcat)
3.3 request功能:
3.3.1 獲取請求消息數據
1. 獲取請求行數據
* GET /day14/demo1?name=zhangsan HTTP/1.1
* 方法:
1. 獲取請求方式 :GET
* String getMethod()
2. (*)獲取虛擬目錄:/day14
* String getContextPath()
3. 獲取Servlet路徑: /demo1
* String getServletPath()
4. 獲取get方式請求參數:name=zhangsan
* String getQueryString()
5. (*)獲取請求URI:/day14/demo1
* String getRequestURI(): /day14/demo1
* StringBuffer getRequestURL() :http://localhost/day14/demo1
* URL:統一資源定位符 : http://localhost/day14/demo1
* URI:統一資源標識符 : /day14/demo1
6. 獲取協議及版本:HTTP/1.1
* String getProtocol()
7. 獲取客戶機的IP地址:
* String getRemoteAddr()
2. 獲取請求頭數據
* 方法:
* (*)String getHeader(String name):通過請求頭的名稱獲取請求頭的值
* Enumeration<String> getHeaderNames():獲取所有的請求頭名稱
3. 獲取請求體數據:
* 請求體:只有POST請求方式,才有請求體,
在請求體中封裝了POST請求的請求參數
* 步驟:
1. 獲取流對象
* BufferedReader getReader():獲取字符輸入流,只能操作字符數據
* ServletInputStream getInputStream():獲取字節輸入流,可以操作所有類型數據
2. 再從流對象中拿數據
3.3.2 其他功能:獲取請求參數通用方式:不論get還是post請求方式都可以使用下列方法來獲取請求參數:
1. String getParameter(String name):根據參數名稱獲取值 username=zs
2. String[] getParameterValues(String name):根據參數名稱獲取參數值的數組 hobby=xx&hobby=game
3. Enumeration<String> getParameterNames():獲取所有請求的參數名稱
4. Map<String,String[]> getParameterMap():獲取所有參數的map集合
* 中文亂碼問題:
* get方式:tomcat 8 已經將get方式亂碼問題解決了
* post方式:會亂碼
* 解決:在獲取參數前,設置request的編碼為
request.setCharacterEncoding("utf-8");
3.3.3 請求轉發:一種在服務器內部的資源跳轉方式
1. 步驟:
1. 通過request對象獲取請求轉發器對象:
RequestDispatcher getRequestDispatcher(String path)
2. 使用RequestDispatcher對象來進行轉發:
forward(ServletRequest request, ServletResponse response)
2. 特點:
1. 瀏覽器地址欄路徑不發生變化
2. 只能轉發到當前服務器內部資源中。
3. 轉發是一次請求
3.3.4. 共享數據:
* 域對象:一個有作用范圍的對象,可以在范圍內共享數據
* request域:代表一次請求的范圍,一般用于請求轉發的多個資源中共享數據
* 方法:
1. void setAttribute(String name,Object obj):存儲數據
2. Object getAttitude(String name):通過鍵獲取值
3. void removeAttribute(String name):通過鍵移除鍵值對
3.3.5. 獲取ServletContext:
* ServletContext getServletContext()
四、案例:用戶登錄
* 用戶登錄案例需求:
1.編寫login.html登錄頁面
username & password 兩個輸入框
2.使用Druid數據庫連接池技術,操作mysql,day14數據庫中user表
3.使用JdbcTemplate技術封裝JDBC
4.登錄成功跳轉到SuccessServlet展示:登錄成功!用戶名,歡迎您
5.登錄失敗跳轉到FailServlet展示:登錄失敗,用戶名或密碼錯誤
* 分析
* 開發步驟
1. 創建項目,導入html頁面,配置文件,jar包
2. 創建數據庫環境
CREATE DATABASE day14;
USE day14;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
3. 創建包cn.itcast.domain,創建類User
package cn.itcast.domain;
/**
* 用戶的實體類
*/
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id=id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username=username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password=password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
4. 創建包cn.itcast.util,編寫工具類JDBCUtils
package cn.itcast.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具類 使用Durid連接池
*/
public class JDBCUtils {
private static DataSource ds ;
static {
try {
//1.加載配置文件
Properties pro=new Properties();
//使用ClassLoader加載配置文件,獲取字節輸入流
InputStream is=JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化連接池對象
ds=DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取連接池對象
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 獲取連接Connection對象
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
5. 創建包cn.itcast.dao,創建類UserDao,提供login方法
package cn.itcast.dao;
import cn.itcast.domain.User;
import cn.itcast.util.JDBCUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* 操作數據庫中User表的類
*/
public class UserDao {
//聲明JDBCTemplate對象共用
private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登錄方法
* @param loginUser 只有用戶名和密碼
* @return user包含用戶全部數據,沒有查詢到,返回null
*/
public User login(User loginUser){
try {
//1.編寫sql
String sql="select * from user where username=? and password=?";
//2.調用query方法
User user=template.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();//記錄日志
return null;
}
}
}
6. 編寫cn.itcast.web.servlet.LoginServlet類
package cn.itcast.web.servlet;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.設置編碼
req.setCharacterEncoding("utf-8");
//2.獲取請求參數
String username=req.getParameter("username");
String password=req.getParameter("password");
//3.封裝user對象
User loginUser=new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
//4.調用UserDao的login方法
UserDao dao=new UserDao();
User user=dao.login(loginUser);
//5.判斷user
if(user==null){
//登錄失敗
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else{
//登錄成功
//存儲數據
req.setAttribute("user",user);
//轉發
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
7. 編寫FailServlet和SuccessServlet類
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//獲取request域中共享的user對象
User user=(User) request.getAttribute("user");
if(user !=null){
//給頁面寫一句話
//設置編碼
response.setContentType("text/html;charset=utf-8");
//輸出
response.getWriter().write("登錄成功!"+user.getUsername()+",歡迎您");
}
}
@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//給頁面寫一句話
//設置編碼
response.setContentType("text/html;charset=utf-8");
//輸出
response.getWriter().write("登錄失敗,用戶名或密碼錯誤");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
8. login.html中form表單的action路徑的寫法
* 虛擬目錄+Servlet的資源路徑
9. BeanUtils工具類,簡化數據封裝
* 用于封裝JavaBean的
1. JavaBean:標準的Java類
1. 要求:
1. 類必須被public修飾
2. 必須提供空參的構造器
3. 成員變量必須使用private修飾
4. 提供公共setter和getter方法
2. 功能:封裝數據
2. 概念:
成員變量:
屬性:setter和getter方法截取后的產物
例如:getUsername() --> Username--> username
3. 方法:
1. setProperty()
2. getProperty()
3. populate(Object obj , Map map):將map集合的鍵值對信息,封裝到對應的JavaBean對象中
文共2678字,預計學習時長15分鐘
圖源:unsplash
使用JavaScript時,總會有各種需要發出調用請求的情況,進行ajax調用什么技術更適合呢?
最初,盡管有一些方法可以在不刷新頁面的情況下從服務器提取數據,但它們通常依賴于笨拙的技術。直到微軟為Outlook電子郵件客戶端的替代瀏覽器開發了XMLHttpRequest。它在2006年成為了Web標準。
2015年,Fetch API隨ES6引入。通用的Request和Response接口提供了一致性,而Promises允許更容易的鏈接和沒有回調的異步/等待。Fetch簡潔,優雅且易于理解,但是還有其他不錯的選擇,本文將簡要的含義、語法以及利弊。
以下代碼展示了使用不同替代方法的基本HTTP GET和POST示例。現在開始吧~
XMLHttpRequest對象可用于從Web服務器請求數據。它是這次比較中最早的方法,盡管其他選擇都優于它,但由于其向后兼容性和成熟度,它仍然有效且有用。
得到:
var req=new XMLHttpRequest();//The onreadystatechange property
//specifies a function to be
//executed every time the status
//of the XMLHttpRequest changes
req.onreadystatechange=function() {
if (this.readyState==4 &&this.status==200) {
//The responseText property
//returns a text string
console.log(xhttp.responseText)
//Do some stuff
}
};req.open("GET", "http://dataserver/users", true);
req.send();
發送:
varformData=new FormData();
formData.append("name", "Murdock");
var req=new XMLHttpRequest();
req.open("POST", "http://dataserver/update");
req.send(formData);
優點:
· 不需要從外部源加載
· 向后兼容性
· 成熟/穩定
· 在所有瀏覽器中均可使用
· 是原生瀏覽器API
缺點:
· 支持回調地獄
· 笨拙冗長的語法
· Fetch能自然地替代它
圖源:unsplash
Qwest是一個基于Promise的簡單ajax庫,它支持XmlHttpRequest2的獨立數據,例如ArrayBuffer,Blob和FormData。
得到:
qwest.get('http://dataserver/data.json')
.then(function(xhr, response) {
// ...do some stuff whith data
});
發送:
qwest.post('http://dataserver/update',{
firstname: 'Murdock',
age: 30
})
.then(function(xhr, response) {
// Make some useful actions
})
.catch(function(e, xhr, response) {
// Process the error
});
優點:
· 可以建立請求限制
· 基于Promise
缺點:
· 并非所有瀏覽器上都可使用XmlHttpRequest2
· 非原生
· 必須從外部源加載
該庫在不久前被廣泛用于發出HTTP異步請求。jQuery的所有Ajax方法都返回XMLHTTPRequest對象的超集
得到:
$.ajax({
url: 'http://dataserver/data.json'
}).done(function(data) {
// ...do some stuff whith data
}).fail(function() {
// Handle error
});
發送:
$.ajax({
type: "POST",
url: 'http://dataserver/update',
data: data,
success: successCallBack,
error: errorCallBack,
dataType: dataType
});
優點:
· 良好的支持和文檔
· 可配置的對象
· 在許多項目中使用
· 學習曲線低
· 它返回XMLHttpRequest對象,因此可以中止請求
缺點:
· 非原生
· 必須從外部源加載
· 沒有與Promises結合
· 對于原生ES6 Fetch不是必需的。
圖源:unsplash
基于Promise的HTTP庫,用于在瀏覽器和Nodejs上執行HTTP請求。
得到:
axios({
url: 'http://dataserver/data.json',
method: 'get'
})
發送:
axios.post('http://dataserver/update',{
name: 'Murdock'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
優點:
· 使用promise避免回調地獄
· 在瀏覽器和Nodejs上均可使用
· 支持上傳進度
· 可以設置響應超時
· 通過簡單地向其傳遞配置對象即可配置請求
· Axios已實現可撤銷的promise提議
· 自動將數據轉換為JSON
缺點:
· 非原生
· 必須從外部源加載
SuperAgent是ajax API,旨在提供靈活性,可讀性和較低的學習曲線。它也可以與Node.js一起使用。
得到:
request('GET','http://dataserver/data.json').then(
success, failure);
.query()方法接受對象,這些對象與GET方法一起使用時將形成查詢字符串。以下代碼將產生路徑/ dataserver / search?name=Manny&lastName=Peck&order=desc。
request
.get('/dataserver/search')
.query({ name: 'Templeton' })
.query({ lastname: 'Peck' })
.query({ order: 'desc' })
.then(res=> {console.dir(res)}
});
發送:
request
.post('http://dataserver/update')
.send({ name: 'Murdock' })
.set('Accept', 'application/json')
.then(res=> {
console.log('result' +JSON.stringify(res.body));
});
優點:
· 基于Promise
· 在Node.js和瀏覽器中均可使用
· 可以調用request.abort()方法中止請求
· 社區的知名庫
· 發出HTTP請求的無縫接口
· 出現故障時支持重試請求
缺點:
· 它不支持以XMLHttpRequest的形式監視加載進度
· 非原生
· 必須從外部源加載
圖源:unsplash
Http-client允許使用JavaScript的訪存API組成HTTP客戶端。
得到:
//usingES6 modules
import { createFetch, base, accept, parse } from 'http-client'const fetch=createFetch(
base('http://dataserver/data.json'),
accept('application/json'),
parse('json')
)fetch('http://dataserver/data.json').then(response=> {
console.log(response.jsonData)
})
發送:
//usingES6 modules
import { createFetch, method, params } from 'http-client'const fetch=createFetch(
params({ name: 'Murdock' }),
base('http://dataserver/update')
)
優點:
· 在Node.js和瀏覽器中均可使用
· 由服務器端工作人員使用
· 基于Promise
· 提供頭部保護裝置,以提高CORS的安全性
缺點:
· 必須從外部源加載
· 非原生
Fetch是原生瀏覽器API,用于發出替代XMLHttpRequest的請求。與XMLHttpRequest相比,Fetch使網絡請求更容易。Fetch API使用Promises避免XMLHttpRequest回調地獄。
得到:
//WithES6 fetch
fetch('http://dataserver/data.json')
.then(data=> {
// ...do some stuff whith data
}).catch(error=> {
// Handle error
});
發送:
fetch('http://dataserver/update',{
method: 'post',
headers: {
'Accept': 'application/json,text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({name: 'Murdock'})
}).then(res=>res.json())
.then(res=> console.log(res));//ORwith ES2017 for example(async ()=> {
const response=awaitfetch('http://dataserver/update', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify({name='Murdock'})
});const result=awaitresponse.json();console.log(result);
})();
優點:
· 是原生瀏覽器API
· Fetch基本上是經過完善的XMLHttpRequest
· 友好且易于學習
· 與大多數最近使用的瀏覽器兼容
· 是原生XMLHttpRequest對象的自然替代
· 學習曲線低
· 不需要從外部源加載它
· 使用promises避免回調地獄
· 不需要更多依賴項
缺點:
· 處理JSON數據的過程分為兩步。第一個是發出請求,然后第二個是在響應時調用.json()方法。對于Axios,默認情況下會收到JSON響應。
· 從Fetch()返回的Promise僅在網絡故障或任何阻止請求完成的情況發生時拒絕。即使響應為HTTP 404或500,也不會拒絕HTTP錯誤狀態。
· 缺乏其他庫的一些有用功能,例如:取消請求。
· 默認情況下,Fetch不會從服務器發送或接收Cookie,如果站點依賴于維持用戶會話,則會導致未經身份驗證的請求。但是可以通過添加以下內容來啟用:
{credentials: “same-origin.”}
圖源:unsplash
Fetch是一個新標準,新版本的Chrome和Firefox無需使用任何其他庫就可支持它。
此外,Axios,SuperAgent或其他庫都有適合的文檔,易于使用,并且學習曲線不太高。在某些情況下,它們可以提供Fetch不具有的功能。
Fetch在JavaScript里是原生的,足以滿足項目需求。如果沒有特殊需求,我認為Fetch就是最合適的選擇。
留言點贊關注
我們一起分享AI學習與發展的干貨
如轉載,請后臺留言,遵守轉載規范
*請認真填寫需求信息,我們會在24小時內與您取得聯系。