<-
Apache > HTTP Server > 文件 > 版本 2.4 > 操作指南/教學

HTTP/2 指南

可用的語言:  en  |  es  |  fr 

這是 Apache httpd 中 HTTP/2 執行實作的操作指南。這項功能已準備好提供服務,而介面和指令預期會保持版本的一致性。

Support Apache!

另請參閱

top

HTTP/2 協定

HTTP/2 是全球最成功的應用層協定 HTTP 的進化版本。它的重點在更有效率地使用網路資源。它不會改變 HTTP 的基本原理和語意。還是有要求和回應,以及標頭等等。因此,如果您已經知道 HTTP/1,就已經知道 HTTP/2 的 95% 了。

已經有許多關於 HTTP/2 及其運作的文章。最具規範性的當然是它的 RFC 7540也有較易閱讀的格式,僅供參考)。因此,您可以在這裡找到基礎知識。

但是,RFC 實際上並不容易閱讀。最好是先了解這項功能想要什麼,然後再讀 RFC 了解它如何做到。一篇更好的入門文件是 HTTP/2 說明,作者是 curl 的作者,Daniel Stenberg。它有越來越多語言的版本!

時間不夠,沒看完:在閱讀本文時,有一些新的專有名詞和問題要注意

top

Apache httpd 中的 HTTP/2

HTTP/2 通訊協定由「httpd 模組」實作,恰如其名 mod_http2。他實作 RFC 7540 所描述的一組完整功能,並支援安全文字傳輸(http:)及安全(https:)連線上的 HTTP/2。安全文字傳輸變體稱為「h2c」,安全的稱為「h2」。h2c 允許直接模式,以及透過初始 HTTP/1 傳輸的「Upgrade:」。

HTTP/2 的其中一項提供網頁開發人員新功能的特色,便是 伺服器推送。請參閱那一段,了解網頁應用程式如何加以利用。

top

以支援 HTTP/2 的方式建立 httpd

mod_http2nghttp2 的函式庫做為實作基礎。為了建立 mod_http2,您需要在系統安裝至少 1.2.1 版的 libnghttp2

當您使用 ./configure 配置 Apache httpd 原始碼樹時,需要給它「--enable-http2」做為額外的引數,以觸發建立模組。如果您的 libnghttp2 位於不尋常的目錄(根據您的作業系統而定),可以使用「--with-nghttp2=<路徑>」向 configure 通知其位置。

雖然對大多數人來說,這應該是可行的,但有些人可能偏好在此模組中使用靜態連結的 nghttp2。對他們而言,有「--enable-nghttp2-staticlib-deps」選項。它的運作方式與 Openssl 到 mod_ssl 的靜態連結相當類似。

說到 SSL,您需要了解到許多瀏覽器只會在 https: 的網址上使用 HTTP/2,因此您需要一個支援 SSL 的伺服器。不僅如此,您需要的 SSL 函式庫必須支援 ALPN 延伸功能。如果您使用 Openssl,您至少需要 1.0.2 版。

top

基本設定

當您建立了包含 mod_http2httpd 時,需要進行一些基本組態才能啟用它。和所有 Apache 模組一樣,您需要載入它的第一件事

LoadModule http2_module modules/mod_http2.so

您需要新增至伺服器組態的第二個指令是

Protocols h2 http/1.1

這允許 h2(安全的變體)成為您的伺服器連線上的首選通訊協定。當您想要啟用所有 HTTP/2 變體時,您只要寫

Protocols h2 h2c http/1.1

依您將此指令放置的位置,它會影響所有連線或只影響特定虛擬主機的連線。您可以像下面一樣嵌套它

Protocols http/1.1
<VirtualHost ...>
    ServerName test.example.org
    Protocols h2 http/1.1
</VirtualHost>

這讓連線只允許 HTTP/1,除了 test.example.org 的 SSL 連線,它提供 HTTP/2。

選擇強力的 SSLCipherSuite

SSLCipherSuite 需要設定成強力的 TLS 加密模組。目前的 mod_http2 版本並未強制任何加密模組,但大多數客戶端會強制加密。將瀏覽器指向有啟用 h2 的伺服器,但使用不適當的加密模組,會讓它直接拒絕連線並退回 1.1 的 HTTP。這是初次為 HTTP/2 設定 httpd 時常見的錯誤,因此請記住它,以避免漫長的除錯時段!如果您想確認要選擇的加密模組,請避免 HTTP/2 TLS 拒絕清單 中所列的模組。

提及通訊協定的順序也相關。預設情況下,第一個通訊協定是最優先的通訊協定。當客戶端提供多個選擇時,會選擇最左邊的通訊協定。在

Protocols http/1.1 h2

中,最優先的通訊協定是 HTTP/1,除非客戶端支援 h2,否則它將會一直被選取。由於我們希望與支援它的客戶端通訊中使用 HTTP/2,因此更好的順序是

Protocols h2 h2c http/1.1

排序中還有另一件要注意的事項:客戶端也有自己的首選項。如果要的話,您可以設定您的伺服器選擇客戶端最優先的通訊協定

ProtocolsHonorOrder Off

讓您所寫的通訊協定順序變得無關緊要,只有客戶端的排序會影響決定。

最後要注意的事項:您設定的通訊協定不會檢查正確性或拼寫。您可以提及不存在的通訊協定,因此無須以任何 <IfModule> 檢查保護 Protocols

如需有關組態的更進階提示,請參閱 模組部分中關於調整大小的說明如何使用同一個憑證管理多個主機

top

MPM 組態

支援 HTTP/2 的所有多工處理模組都會附有 httpd。不過,如果您使用 prefork mpm,會有嚴格的限制。

prefork 中, mod_http2 每個連線將只處理一個請求。但瀏覽器等用戶端會同時發出多個請求。如果其中一個請求花了很長的時間處理(或為長時間輪詢),則其他請求將會停止。

預設情況下,mod_http2 不會解決此問題。原因是只要您執行未準備好進行多執行緒處理的處理引擎,例如會發生故障且不只一個請求,此時只會選擇 prefork

如果您的設定可以處理,現今最佳的方式是設定 event mpm(如果您的平台支援)。

如果您真的無法使用 prefork,又想有多個請求,您可以調整 H2MinWorkers 達到這個目標。不過,如果導致中斷,則兩者之間的影響您自行負責。

top

用戶端

幾乎所有現代瀏覽器都支援 HTTP/2,但僅在 SSL 連線中使用:Firefox (v43)、Chrome (v45)、Safari(自 v9)、iOS Safari(v9)、Opera(v35)、Chrome Android(v49)和 Internet Explorer(Windows 10 上的 v11)(來源)。

其他用戶端和伺服器會列於 實作清單 中,其中包含 c、c++、common lisp、dart、erlang、haskell、java、nodejs、php、python、perl、ruby、rust、scala 和 swift 的實作。

幾個非瀏覽器用戶端實作支援明文傳輸的 HTTP/2,h2c。最靈活的為 curl

top

除錯 HTTP/2 的有用工具

首先要提到的工具當然是 curl。請確定您的版本支援 HTTP/2,方法是檢查其 特性

    $ curl -V
    curl 7.45.0 (x86_64-apple-darwin15.0.0) libcurl/7.45.0 OpenSSL/1.0.2d zlib/1.2.8 nghttp2/1.3.4
    Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 [...] 
    Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2
    

Mac OS homebrew 注意事項

brew 安裝 curl --with-openssl --with-nghttp2

而對於更深度的檢查,請使用 wireshark

nghttp2 套件也包含用戶端,例如

Chrome 透過 特殊 net-internals 頁面,提供其連線中的詳細 HTTP/2 記錄。另外也有 ChromeFirefox 的擴充功能,可顯示您的瀏覽器何時使用 HTTP/2。

top

伺服器推送

HTTP/2 協定允許伺服器將回應推送至從未要求過的用戶端。會話的語氣為:「這裡有一個您從未發出的請求,而回應很快就會抵達...」

但有使用限制:用戶端可以停用此功能,而伺服器只能在來自用戶端的請求中進行推送。

目的是讓伺服器傳送資源給客戶端,這些資源通常是客戶端已請求的 HTML 頁面中所屬的 css 或 javascript 資源。css 所引用的圖像組等等。

對客戶端的優點是,它節省傳送請求所需的時間,從幾毫秒到半秒不等,具體取決於地球上兩者的位置。缺點是客戶端可能會收到它快取中已有的內容。當然,HTTP/2 允許提前取消此類請求,但仍然會浪費資源。

總結來說:如何最佳使用 HTTP/2 的這項功能沒有單一的好策略,而且每個人仍在嘗試中。所以,您如何使用 Apache httpd 嘗試呢?

mod_http2 檢視特定格式的 Link 標題的回應標題

Link </xxx.css>;rel=preload, </xxx.js>; rel=preload

如果連線支援 PUSH,這兩個資源將會傳送給客戶端。作為 Web 開發人員,您可以在應用程式回應或透過以下方式設定伺服器來設定這些標題

<Location /xxx.html>
    Header add Link "</xxx.css>;rel=preload"
    Header add Link "</xxx.js>;rel=preload"
</Location>

如果您想使用 preload 連結而不會觸發 PUSH,您可以使用 nopush 參數,就像這樣

Link </xxx.css>;rel=preload;nopush

或者您可以使用指令完全停用伺服器的 PUSH

H2Push Off

還有更多

模組會記錄每個連線已 PUSH 的內容(基本上是 URL 的雜湊),並且不會將相同的資源 PUSH 兩次。當連線關閉時,這些資訊會被捨棄。

有人在思考客戶端如何告訴伺服器它已經有哪些內容,所以可以避免 PUSH 這些內容,但這一切都還在大量實驗中。

mod_http2 已執行的另一項實驗性質草案是 Accept-Push-Policy 標題欄位,客戶端可以定義它接受什麼樣的 PUSH 類型。

PUSH 並不總會觸發預期或期望的請求/回應/效能。網路上可以找到關於這個主題的各種研究,解釋了優缺點,以及客戶端和網路的不同特點如何影響結果。例如:單憑伺服器 PUSH 資源並不表示瀏覽器會實際使用資料。

影響被 PUSH 的回應的主要因素是模擬的請求。PUSH 的請求網址由應用程式提供,但請求標題從何而來?例如,PUSH 請求會要求 accept-language 標題嗎?如果是的話,其值是什麼?

Apache 會查看原始請求(觸發 PUSH 的請求),並將下列標題複製到 PUSH 請求:user-agentacceptaccept-encodingaccept-languagecache-control

忽略所有其他標頭。Cookie 也會無法複製。推送需要 Cookie 的資源將無法順利運作。這可能會引起爭議。但除非事先與瀏覽器有更明確的討論,否則讓我們謹慎行事,不要在平常不會顯示 Cookie 的地方顯示 Cookie。

top

早期提示

推動資源的替代方法是,在回應準備妥當之前,將 連結 標頭傳送至用戶端。這是使用 HTTP 的「早期提示」功能,並且在 RFC 8297 中有說明。

如需使用此功能,您需要透過以下方式在伺服器上明確啟用:

H2EarlyHints on

(它預設未啟用,因為一些較舊的瀏覽器無法順利處理此類回應。)

如已啟用這項功能,您可以使用指令 H2PushResource 來觸發早期提示和資源推播。

<Location /xxx.html>
    H2PushResource /xxx.css
    H2PushResource /xxx.js
</Location>

當伺服器開始處理請求時,會立即向用戶端傳送 "103 早期提示" 回應。這可能遠早於決定第一個回應標頭的時間,具體取決於您的網路應用程式。

如果已啟用 H2Push,則它將會在 103 回應之後立即開始推播。但是,如果停用 H2Push,則 103 回應仍會傳送給用戶端。

可用的語言:  en  |  es  |  fr 

top

留言

注意事項
此非問答區。放在此處的留言應針對改善文件或伺服器的建議,且如果我們的管理員已實施或認為無效/離題,則可能會予以刪除。對於如何管理 Apache HTTP Server 的問題應轉交至我們的 IRC 頻道,#httpd,在 Libera.chat 上,或發送至我們的 郵件清單