在過去的十年中,HTTP社區(qū)一直忙于對(duì)Web協(xié)議現(xiàn)代化,對(duì)核心規(guī)范進(jìn)行了多次修訂與擴(kuò)展,從HTTP/2以及現(xiàn)在的 HTTP/3。不幸的是,從最初到現(xiàn)在我們定義和使用HTTP header的方式并沒有什么大的改變,由于未指定的Headers(以及處理方式的多樣性)引起的互通性問題,為開發(fā)人員帶來很多痛苦,甚至引發(fā)安全問題。
●HTTP標(biāo)頭有什么問題?●
大多數(shù)Web開發(fā)人員都熟悉HTTP標(biāo)頭;如Content-Length、Cache-Control和Cookie之類。它們會(huì)攜帶請求和響應(yīng)的元數(shù)據(jù),通常,這部分?jǐn)?shù)據(jù)是消息發(fā)送者由于某種原因無法放入正文內(nèi)容的信息,或者是消息接收者無需查看正文內(nèi)容即可獲得的信息。 因?yàn)闃?biāo)頭需要由許多不同的客戶端和服務(wù)器,代理服務(wù)和CDN處理(通常在消息的生存期內(nèi)不止一次),所以大家希望它們易于處理,高效解析并且定義明確句法。 HTTP將頭值(更恰當(dāng)?shù)恼f是字段值,因?yàn)樗鼈円部赡艹霈F(xiàn)在主體后面的尾部字段中)定義為一個(gè)約束很少的“八進(jìn)制序列”(即字節(jié)),盡管建議是ASCII字節(jié)。它還建議在ABNF中定義標(biāo)題,如果用逗號(hào)分隔字段的值,則可以將同名的多個(gè)字段組合在同一行上。 因此,每個(gè)標(biāo)題字段都有自己的唯一定義,需要知道它才能解析值。一些領(lǐng)域作者使用ABNF來做到這一點(diǎn);另一些人使用示例。有些只是讓你根據(jù)你以前看到的價(jià)值觀來猜測。 例如,考慮年齡年限標(biāo)題。它是核心HTTP規(guī)范的一部分,所以它應(yīng)該是定義明確的,而且它只是一個(gè)簡單的整數(shù)。
Age: 42
由此ABNF指定:
Age = delta-secondsdelta-seconds = 1*DIGITDIGIT = %x30-39 ; 0-9
起初這似乎很簡單——0到9之間數(shù)字的一個(gè)到多個(gè)實(shí)例。但在實(shí)際考慮中,如果一個(gè)實(shí)現(xiàn)遇到這些現(xiàn)實(shí)標(biāo)題中的任何一個(gè),它應(yīng)該做什么:
Age: 0, 60Age: 60, 0Age: 50mAge: abc234Age: 60;ms=212
它不是那么簡單,因?yàn)闇y試真正的緩存需要用年限顯示。 因此,當(dāng)同一個(gè)人正在編寫生成和消耗消息頭的代碼而沒有其他人時(shí),示例或ABNF可能是一個(gè)足夠的定義,但如果有多個(gè)實(shí)現(xiàn)生成和解析值,則互操作性是很糟的。 每個(gè)標(biāo)題作者都必須記住要解決一個(gè)問題列表,這些問題涉及如何處理重復(fù)值、案例規(guī)范化、無論是單個(gè)項(xiàng)目還是列表等等。通常,他們不會(huì)處理這些問題,這意味著開發(fā)者通常以不同的方式自行選擇。 未充分指定的消息頭也是安全問題的來源;如果實(shí)現(xiàn)解析消息頭的方式不同,它們的行為可能會(huì)不同,從而導(dǎo)致Response Splitting這類的攻擊。 瀏覽器供應(yīng)商已經(jīng)足夠關(guān)注這些問題,開始像CSP算法那樣定義頭。也就是說,他們費(fèi)力地定義解析和序列化算法,然后創(chuàng)建測試用例。這種方法對(duì)字段語法的模糊性較小,實(shí)現(xiàn)之間的差異較小。然而,它仍然是一次性的;它只有助于澄清特定標(biāo)題的算法。對(duì)于規(guī)范的作者來說,去努力并確保它是正確的也是很累的-所以大多數(shù)標(biāo)題作者都不會(huì)費(fèi)心。它還為實(shí)現(xiàn)者創(chuàng)建了大量繁忙的工作,因?yàn)樗麄冃枰謩e實(shí)現(xiàn)每個(gè)新的頭的解析器。
●引入結(jié)構(gòu)化領(lǐng)域●
HTTP工作組已經(jīng)非常清楚了這類問題,幾年前我們開始嘗試定義一些更好的方法,使人們可以使用這些東西來創(chuàng)建新的字段。經(jīng)過幾次嘗試后,我們確定了一種最初稱為結(jié)構(gòu)化標(biāo)題的方法,但我們現(xiàn)在(更正確地)稱之為“結(jié)構(gòu)化字段”。 結(jié)構(gòu)化字段是一個(gè)定義良好的數(shù)據(jù)類型庫,在HTTP頭和拖車中可能有用,包括字符串、Tokens、布爾值、整數(shù)、小數(shù)和字節(jié)序列作為原子“Item”類型,以及這些項(xiàng)的列表和字典。重要的是,它定義了每種類型的精確解析和序列化算法,以及錯(cuò)誤處理和詳細(xì)的測試套件-所有這些都有助于確?;ゲ僮餍浴? 這允許新頭字段的作者根據(jù)這些類型定義它。例如,他們可以說“這是一個(gè)字符串列表”,人們將知道如何使用一個(gè)現(xiàn)成的庫來明確地解析和生成標(biāo)頭,而不是編寫特定于頭的代碼。
Example-Header: "blue", "sort of red", "green"每個(gè)項(xiàng)目也可以有參數(shù),或鍵/值對(duì)的額外信息。參數(shù)是一種重要的可擴(kuò)展性機(jī)制,它允許消息頭隨著時(shí)間的推移而演變。
Example-Header: "blue"; websafe, "sort of red"; author="sue", "green"
遞歸的形式也很有限;列表和字典值也可以包含列表,例如:
Example-Header: people=(joanna stacy), places=("new york" "rome") 內(nèi)部列表中的每個(gè)項(xiàng)目以及內(nèi)部列表本身都可以進(jìn)行參數(shù)化。 你可能會(huì)注意到,這些消息頭看起來很像許多現(xiàn)有的HTTP字段。這是通過設(shè)計(jì)實(shí)現(xiàn)的;不僅對(duì)開發(fā)人員來說是舒適的,它還允許通過結(jié)構(gòu)化字段實(shí)現(xiàn)生成許多現(xiàn)有字段,并且通常它們也可以被解析。例如,許多Cache-Control報(bào)頭都是有效的“結(jié)構(gòu)化字段”,即使它沒有定義為一個(gè):
Cache-Control: max-age=3600, immutable
很不幸你還不能將結(jié)構(gòu)化字段用于現(xiàn)有的標(biāo)頭,也無法僅通過查看它來判斷給定字段是否是結(jié)構(gòu)化字段;你必須知道它的定義值,因?yàn)榻Y(jié)構(gòu)化字段至少在現(xiàn)在才用于新字段。
●使用結(jié)構(gòu)化字段獲得更好的性能●
指定新字段更容易,并使它們更安全和更可互操作,這對(duì)HTTP來說是一個(gè)顯著的改進(jìn)。如果結(jié)構(gòu)化字段也能幫助HTTP性能呢?他們有兩種方法可以幫助你。顯然,這些都是投機(jī)性的好處,但它們?nèi)匀皇怯腥さ恼務(wù)摗? 首先是解析效率。由于傳統(tǒng)的HTTP消息頭是文本形式的,解析器必須接觸字符串中的每個(gè)字節(jié),有時(shí)需要多次,有時(shí)會(huì)將其復(fù)制并重新復(fù)制到內(nèi)存的不同部分。這是一個(gè)固有的低效過程,HTTP/2和HTTP/3是二進(jìn)制協(xié)議而不是文本協(xié)議的原因之一。 在結(jié)構(gòu)化字段之前,我們對(duì)此無能為力,因?yàn)镠TTP消息頭的定義非常松散。結(jié)構(gòu)化字段中定義良好的數(shù)據(jù)類型會(huì)改變這一點(diǎn)?,F(xiàn)在,我們可以定義一個(gè)新的,二進(jìn)制序列化的任何頭使用他們。 二元結(jié)構(gòu)化字段是定義這種序列化的草案建議,以定義這樣的序列化。它使用HTTP/2(和/3)SETTINGS機(jī)制來協(xié)商對(duì)替代序列化的支持,并利用結(jié)構(gòu)化字段與許多現(xiàn)有標(biāo)題字段的語法的相似性將其返回到一組已經(jīng)廣泛使用的標(biāo)題字段上,如果它們無法解析,則返回到不透明的文本。 二進(jìn)制序列化將幫助性能多少?由于預(yù)期會(huì)減少CPU負(fù)載,因此它應(yīng)該減少請求處理的延遲并提高可伸縮性。我們還沒有真實(shí)的統(tǒng)計(jì),但是如果你考慮許多標(biāo)題所采取的路徑-從JavaScript到瀏覽器,然后再到CDN,通過多個(gè)CDN節(jié)點(diǎn)到源服務(wù)器,再到應(yīng)用程序代碼本身。累積節(jié)省的潛力是有吸引力的。 結(jié)構(gòu)化字段可能有助于性能的第二種方法是通過提高壓縮效。HTTP/2為頭和拖車字段引入了HPACK壓縮。雖然它的前身SPDY使用GZIP,但由于CRIME攻擊,它被發(fā)現(xiàn)是不安全的。因此,HPACK(及其繼承者QPACK)通過引用整個(gè)字段值來壓縮字段;如果它的任何一部分發(fā)生變化,它就不能使用以前的引用(有時(shí)會(huì)對(duì)壓縮效率產(chǎn)生令人驚人的影響)。 之所以選擇整值粒度,是因?yàn)橥ㄓ媒馕銎鳠o法理解字段值的結(jié)構(gòu);為了安全起見,我們必須確保攻擊者無法通過猜測部分字段值來探測加密。 對(duì)于結(jié)構(gòu)化字段,現(xiàn)在有一種潛在的方法可以使壓縮算法對(duì)字段中的單個(gè)數(shù)據(jù)類型而不是整個(gè)值進(jìn)行操作。
Cache-Control: max-age=3600, s-maxage=7200, must-revalidate
例如,考慮以下Cache-Control字段: 使用HPACK和QPACK,整個(gè)字段值存儲(chǔ)在動(dòng)態(tài)表中,并且只能由具有完全相同值的未來消息引用。如果我們將其解析為結(jié)構(gòu)化字段并存儲(chǔ)單個(gè)數(shù)據(jù)類型,我們可以存儲(chǔ):
lmax-age
l3600
ls-maxage
l7200
lmust-revalidate
這些變量中的每一個(gè)都可以在將來的標(biāo)頭中出現(xiàn)時(shí)分別引用,從而使壓縮算法更精細(xì),而且效率更高。 早期的原型表明,使用這種技術(shù)的提升對(duì)于Web瀏覽器連接來說效率非常低的,因?yàn)樗鼈兊臉?biāo)題往往是高度重復(fù)的,用多個(gè)字節(jié)(字段值中的每種類型都有一個(gè)字節(jié))替換HPACK中的1字節(jié)引用實(shí)際上會(huì)造成傷害。 對(duì)于從多個(gè)客戶端攜帶流量的連接——例如反向代理和源服務(wù)器上游的CDN所看到的流量——好處可能更明顯;需要更多的實(shí)驗(yàn)。
●長期改善HTTP●
如果上面描述的反向?qū)爰夹g(shù)被捕獲,未來版本的HTTP(或HTTP/2和HTTP/3的擴(kuò)展)可以大大減少使用中的非結(jié)構(gòu)化消息頭的數(shù)量。 二進(jìn)制結(jié)構(gòu)化字段草案描述了兩種實(shí)現(xiàn)方法。如果字段的語法與結(jié)構(gòu)化字段兼容-至少在大多數(shù)情況下-它可以作為一個(gè)發(fā)送,當(dāng)失敗時(shí)返回到明文標(biāo)題。 沒有兼容語法的標(biāo)題需要另一種方法。例如,Date、Last-Modified、Expires和類似的消息頭永遠(yuǎn)不可能是有效的結(jié)構(gòu)化字段。但是,可以將日期表示為整數(shù),結(jié)構(gòu)化字段可以傳遞整數(shù)。 所以,就有這樣的標(biāo)題:
Date: Thu, 09 Apr 2020 09:06:50 GMT
可能會(huì)在適當(dāng)?shù)霓D(zhuǎn)譯跳點(diǎn)上表示為:
SF-Date: 1586423210
這為我們提供了一種方法,可以將所有通用消息頭和額外的元信息作為結(jié)構(gòu)化字段發(fā)送。
●立即使用結(jié)構(gòu)化字段●
結(jié)構(gòu)化字段規(guī)范正處于標(biāo)準(zhǔn)化的最后階段,這意味著它很快會(huì)成為一個(gè)RFC。目前我們已經(jīng)有多個(gè)實(shí)例,包括在Chrome中,許多新的安全頭(例如Fetch元數(shù)據(jù))都是結(jié)構(gòu)化的。 同時(shí),可以通過具體實(shí)現(xiàn)來了解它們是如何工作的。例如,Python http_sfv庫允許從命令行解析它們。 如果你定義了新的消息頭(無論它們是針對(duì)整個(gè)的Web還是僅針對(duì)HTTP API)都可以在RFC發(fā)布后開始使用結(jié)構(gòu)化字段。
-
服務(wù)器
+關(guān)注
關(guān)注
13文章
9795瀏覽量
87984 -
HTTP
+關(guān)注
關(guān)注
0文章
525瀏覽量
33511 -
結(jié)構(gòu)化
+關(guān)注
關(guān)注
0文章
27瀏覽量
10406
原文標(biāo)題:使用結(jié)構(gòu)化的標(biāo)頭字段改善HTTP
文章出處:【微信號(hào):livevideostack,微信公眾號(hào):LiveVideoStack】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評(píng)論請先 登錄
FC光纖頭和SC光纖頭有什么區(qū)別
S32G399ardb3版本中缺少WIC文件IVT標(biāo)頭,怎么解決?
標(biāo)6類網(wǎng)線6類頭不能用什么原因
用MATLAB或者C語言開發(fā)FPGA有什么問題嗎
HTTP 協(xié)議對(duì)于SEO優(yōu)化的影響
如何調(diào)試 HTTP 請求和響應(yīng)
如何使用 cURL 測試 HTTP 協(xié)議
HTTP 1.1 和 HTTP 2.0 的區(qū)別
HTTP 協(xié)議的工作原理
HTTP緩存頭的使用 本地緩存與遠(yuǎn)程緩存的區(qū)別
HTTP海外趨勢洞察:未來網(wǎng)絡(luò)發(fā)展的風(fēng)向標(biāo)
網(wǎng)線水晶頭有幾種規(guī)格
sdi頭和bnc頭有什么區(qū)別

評(píng)論