偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

絕了,Go HTTP/2 終于要進(jìn)入標(biāo)準(zhǔn)庫(kù)了?。?!

開(kāi)發(fā) 前端
從 Go 1.6 開(kāi)始,net/http?包就提供了對(duì) HTTP/2 的透明支持。但這個(gè)支持方式有點(diǎn)特別——HTTP/2 的真正實(shí)現(xiàn)其實(shí)在?golang.org/x/net/http2?包里,標(biāo)準(zhǔn)庫(kù)只是把它打包進(jìn)來(lái)。

絕了。最近 Go 社區(qū)有個(gè)重磅消息,HTTP/2 終于要正式進(jìn)入標(biāo)準(zhǔn)庫(kù)了!

這事兒說(shuō)起來(lái)挺有意思的。很多同學(xué)可能都遇到過(guò)這樣的尷尬場(chǎng)景:想配置一下 HTTP/2 的參數(shù),結(jié)果發(fā)現(xiàn)必須要導(dǎo)入 golang.org/x/net/http2 這個(gè)官方的 ”外部“ 包。

圖片圖片

前兩天剛哭訴完 HTTP/3 被擱置。今天我們?cè)賮?lái)聊聊 Go 團(tuán)隊(duì)為什么終于肯把 HTTP/2 搬進(jìn)標(biāo)準(zhǔn)庫(kù),以及這背后的故事。

背景:一個(gè)別扭的設(shè)計(jì)

從 Go 1.6 開(kāi)始,net/http 包就提供了對(duì) HTTP/2 的透明支持。但這個(gè)支持方式有點(diǎn)特別——HTTP/2 的真正實(shí)現(xiàn)其實(shí)在 golang.org/x/net/http2 包里,標(biāo)準(zhǔn)庫(kù)只是把它打包進(jìn)來(lái)。

為什么要這么做呢?主要是為了避免循環(huán)依賴(lài)的問(wèn)題。http2 包依賴(lài) net/http,而 net/http 又要用 http2,這就形成了一個(gè)死循環(huán)。

Go 團(tuán)隊(duì)用了一個(gè)叫 bundle 的工具,把整個(gè) http2 包合并成一個(gè)單獨(dú)的文件(h2_bundle.go),然后塞進(jìn) net/http 里。

圖片圖片

這個(gè)設(shè)計(jì)在早期是有好處的:

  • 可以在 Go 發(fā)布周期之外更新 HTTP/2 實(shí)現(xiàn)
  • 快速迭代,不受兼容性承諾約束
  • 用戶(hù)可以自己選擇 HTTP/2 的版本

有什么問(wèn)題?

但現(xiàn)在問(wèn)題越來(lái)越多了。

1、關(guān)系太復(fù)雜了net/http、h2_bundle.go、golang.org/x/net/http2 三者之間的關(guān)系讓人頭大,新手看了直接懵。

2、修 bug 太麻煩了:每次要給 HTTP/2 打安全補(bǔ)丁,都得在多個(gè)版本之間來(lái)回折騰,backport 的流程異常復(fù)雜。

3、配置不方便:想調(diào)個(gè) HTTP/2 參數(shù)?對(duì)不起,必須導(dǎo)入外部包。而且導(dǎo)入之后,不光配置變了,連實(shí)現(xiàn)都換了,這就很尷尬。

4、開(kāi)發(fā)受限:HTTP/1 和 HTTP/2 的代碼分別在不同的倉(cāng)庫(kù),想要同時(shí)改動(dòng)兩邊的邏輯,幾乎不可能原子化完成。

舉個(gè)例子,之前有個(gè) issue #52459,說(shuō)的是 HTTP/1 和 HTTP/2 都有自己的重試邏輯,導(dǎo)致請(qǐng)求可能被重試多次。

圖片圖片

最簡(jiǎn)單的解決方案是搞一個(gè)統(tǒng)一的重試循環(huán),但因?yàn)榇a分散在兩個(gè)倉(cāng)庫(kù),實(shí)現(xiàn)起來(lái)困難重重。

提案:是時(shí)候搬家了

Go 團(tuán)隊(duì)提出了一個(gè)大膽的計(jì)劃:把 HTTP/2 徹底搬進(jìn)標(biāo)準(zhǔn)庫(kù)。

圖片圖片

具體來(lái)說(shuō),就是把 golang.org/x/net/http2 的實(shí)現(xiàn)挪到 net/http/internal/http2 里。

這是個(gè)內(nèi)部包(internal),普通用戶(hù)不能直接導(dǎo)入。所有新的開(kāi)發(fā)都會(huì)在標(biāo)準(zhǔn)庫(kù)里進(jìn)行。

那老的 x/net/http2 包怎么辦呢?

Go 團(tuán)隊(duì)的計(jì)劃是這樣的:

  1. 在過(guò)渡期內(nèi),繼續(xù)給 x/net/http2 包提供 bug 修復(fù)。
  2. 更新 x/net/http2,讓它在新版本 Go 里直接調(diào)用標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn)。
  3. 等所有還在維護(hù)的 Go 版本都不再使用舊的 vendor 版本后,正式廢棄 x/net/http2

這個(gè)方案很巧妙。既保證了平滑過(guò)渡,又能讓新代碼享受到統(tǒng)一實(shí)現(xiàn)的好處。

新的配置方式

搬進(jìn)標(biāo)準(zhǔn)庫(kù)之后,最直觀的變化就是配置方式變了。以前我們要這樣寫(xiě):

import (
    "net/http"
    "golang.org/x/net/http2"
)

func main() {
    server := &http.Server{
        Addr: ":8080",
    }

    // 必須調(diào)用這個(gè)函數(shù)來(lái)配置 HTTP/2
    http2.ConfigureServer(server, &http2.Server{
        MaxConcurrentStreams: 250,
        IdleTimeout: 5 * time.Minute,
    })
}

現(xiàn)在可以直接在 net/http 里配置了:

import (
    "net/http"
    "time"
)

func main() {
    server := &http.Server{
        Addr: ":8080",
        HTTP2: http.HTTP2Config{
            MaxConcurrentStreams: 250,
            MaxDecoderHeaderTableSize: 4096,
            MaxEncoderHeaderTableSize: 4096,
            MaxReadFrameSize: 16384,
            MaxUploadBufferPerConnection: 1 << 20,
            MaxUploadBufferPerStream: 1 << 20,
            SendPingTimeout: 15 * time.Second,
            PingTimeout: 15 * time.Second,
        },
    }

    server.ListenAndServeTLS("cert.pem", "key.pem")
}

是不是清爽多了?不用再導(dǎo)入外部包,所有配置都在標(biāo)準(zhǔn)庫(kù)里搞定。

客戶(hù)端也是一樣的:

transport := &http.Transport{
    HTTP2: http.HTTP2Config{
        MaxDecoderHeaderTableSize: 4096,
        MaxEncoderHeaderTableSize: 4096,
        MaxReadFrameSize: 16384,
    },
}

client := &http.Client{
    Transport: transport,
}

接下來(lái)我們看下 HTTP2Config 的具體字段。

HTTP2Config 配置詳解

新的 HTTP2Config 結(jié)構(gòu)體統(tǒng)一了服務(wù)端和客戶(hù)端的配置項(xiàng),核心字段包括:

type HTTP2Config struct {
    // MaxConcurrentStreams 指定對(duì)端可以同時(shí)打開(kāi)的流數(shù)量
    // 對(duì)應(yīng) HTTP/2 的 SETTINGS_MAX_CONCURRENT_STREAMS
    // 如果為 0,默認(rèn)值至少為 100
    MaxConcurrentStreams uint32

    // MaxDecoderHeaderTableSize 設(shè)置用于解碼 header 的壓縮表大小
    // 對(duì)應(yīng) SETTINGS_HEADER_TABLE_SIZE,默認(rèn) 4096 字節(jié)
    MaxDecoderHeaderTableSize uint32

    // MaxEncoderHeaderTableSize 設(shè)置用于編碼 header 的壓縮表大小上限
    // 接收到的 SETTINGS_HEADER_TABLE_SIZE 會(huì)被限制在這個(gè)值
    // 默認(rèn) 4096 字節(jié)
    MaxEncoderHeaderTableSize uint32

    // MaxReadFrameSize 指定愿意接收的最大幀大小
    // 對(duì)應(yīng) SETTINGS_MAX_FRAME_SIZE
    // 有效值在 16k 到 16M 之間,默認(rèn)值會(huì)被使用
    MaxReadFrameSize uint32

    // MaxUploadBufferPerConnection 是每個(gè)連接的初始流控窗口大小
    // HTTP/2 規(guī)范不允許小于 65535 或大于 2^32-1
    MaxUploadBufferPerConnection int32

    // MaxUploadBufferPerStream 是每個(gè)流的初始流控窗口大小
    // HTTP/2 規(guī)范不允許大于 2^32-1
    MaxUploadBufferPerStream int32

    // SendPingTimeout 是在連接空閑時(shí)發(fā)送 ping 幀做健康檢查的超時(shí)時(shí)間
    // 如果為 0,不進(jìn)行健康檢查
    SendPingTimeout time.Duration

    // PingTimeout 是 ping 響應(yīng)的超時(shí)時(shí)間,超時(shí)后連接會(huì)被關(guān)閉
    // 如果為 0,使用默認(rèn)值 15 秒
    PingTimeout time.Duration

    // PermitProhibitedCipherSuites 如果為 true,
    // 允許使用 HTTP/2 規(guī)范禁止的加密套件
    PermitProhibitedCipherSuites bool

    // CountError 在發(fā)生 HTTP/2 錯(cuò)誤時(shí)被調(diào)用
    // 用于監(jiān)控指標(biāo)統(tǒng)計(jì),比如 expvar 或 Prometheus
    // errType 只包含 ASCII 字母
    CountError func(errType string)
}

這些配置項(xiàng)涵蓋了 HTTP/2 協(xié)議的核心參數(shù),從并發(fā)控制、緩沖區(qū)大小到健康檢查,基本滿(mǎn)足了日常開(kāi)發(fā)的需求。

協(xié)議版本選擇

另一個(gè)重要的改進(jìn)是協(xié)議版本選擇。以前想禁用 HTTP/2,得這樣寫(xiě):

server := &http.Server{
    TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
}

這寫(xiě)法看起來(lái)就很別扭,對(duì)吧?新的 API 直觀多了:

server := &http.Server{
    Addr: ":8080",
    Protocols: []http.Protocol{http.HTTP1}, // 只用 HTTP/1
}

想同時(shí)支持 HTTP/1 和 HTTP/2,還能指定優(yōu)先級(jí):

server := &http.Server{
    Addr: ":8080",
    Protocols: []http.Protocol{http.HTTP2, http.HTTP1}, // 優(yōu)先 HTTP/2
}

核心觀點(diǎn)在于,新的 Protocols 字段讓協(xié)議選擇變得清晰明了。列表中的順序代表了優(yōu)先級(jí),服務(wù)端會(huì)按這個(gè)順序和客戶(hù)端協(xié)商使用哪個(gè)協(xié)議。

如果不設(shè)置 Protocols,默認(rèn)值是 {HTTP2, HTTP1}。但如果你設(shè)置了 TLSNextProto 并且里面沒(méi)有 "h2" 這個(gè) key,默認(rèn)值就會(huì)變成 {HTTP1}。這樣就保證了向后兼容。

客戶(hù)端的用法也是一樣的:

transport := &http.Transport{
    Protocols: []http.Protocol{http.HTTP2, http.HTTP1},
}

client := &http.Client{Transport: transport}

h2c 支持

還有個(gè)值得一提的改進(jìn)是對(duì) h2c(未加密的 HTTP/2)的支持。

以前想用 h2c,要么得在 DialTLS 里返回未加密連接(這名字就很詭異),要么得用 golang.org/x/net/http2/h2c 包?,F(xiàn)在直接用協(xié)議選擇就行了:

server := &http.Server{
    Addr: ":8080",
    Protocols: []http.Protocol{http.UnencryptedHTTP2},
}

server.ListenAndServe() // 注意不是 ListenAndServeTLS

客戶(hù)端也一樣簡(jiǎn)單:

transport := &http.Transport{
    Protocols: []http.Protocol{http.UnencryptedHTTP2},
}

client := &http.Client{Transport: transport}
resp, err := client.Get("http://example.com") // http:// 不是 https://

簡(jiǎn)單來(lái)說(shuō),Go 團(tuán)隊(duì)新增了一個(gè) UnencryptedHTTP2 常量,專(zhuān)門(mén)用來(lái)表示未加密的 HTTP/2 協(xié)議。

當(dāng) Protocols 同時(shí)包含 HTTP1 和 UnencryptedHTTP2 時(shí),服務(wù)端和客戶(hù)端都會(huì)支持 RFC 7540 Section 3.2 定義的 Upgrade: h2c 頭。服務(wù)端會(huì)把帶 Upgrade: h2c 的 HTTP/1 請(qǐng)求升級(jí)到 HTTP/2,客戶(hù)端也會(huì)發(fā)送這個(gè)頭。

如果只設(shè)置了 UnencryptedHTTP2 而沒(méi)有 HTTP1,那么客戶(hù)端會(huì)對(duì) http:// 開(kāi)頭的 URL 直接使用 HTTP/2。

向后兼容性保障

Go 核心團(tuán)隊(duì)特別注重向后兼容。現(xiàn)有代碼怎么辦?

如果你在用 http2.ConfigureServer 或 http2.ConfigureTransports,代碼還是能正常工作的。這兩個(gè)函數(shù)會(huì)被更新,在新版本 Go 里自動(dòng)把 HTTP2 加到 Protocols 列表里。

如果你通過(guò)設(shè)置 TLSNextProto 為空 map 來(lái)禁用 HTTP/2,這種做法也繼續(xù)有效。

如果你直接用 http2.Server 或 http2.Transport,照樣沒(méi)問(wèn)題。

對(duì)于所有已經(jīng)發(fā)布的 golang.org/x/net/http2 版本,行為會(huì)保持不變——選擇了這個(gè)包的實(shí)現(xiàn),就會(huì)用這個(gè)包的,覆蓋標(biāo)準(zhǔn)庫(kù)的。

但是很無(wú)奈的是,新版本的 golang.org/x/net/http2 在遇到支持非 vendor HTTP/2 的 Go 版本時(shí),會(huì)直接調(diào)用標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn)。除非你用了標(biāo)準(zhǔn)庫(kù)不支持的特性(比如 Server.NewWriteScheduler 或 Transport.ConnPool),否則用的就是標(biāo)準(zhǔn)庫(kù)版本。

總之,老代碼不會(huì)因?yàn)檫@次改動(dòng)而出問(wèn)題。

總結(jié)

HTTP/2 進(jìn)入標(biāo)準(zhǔn)庫(kù)這事兒,說(shuō)白了就是一次技術(shù)債償還。當(dāng)年為了快速迭代選擇了折衷方案,現(xiàn)在該還的債總是要還的。

這次改動(dòng)帶來(lái)的好處很明顯:

  1. 配置更簡(jiǎn)單,不用導(dǎo)入外部包就能配置 HTTP/2 參數(shù)
  2. 維護(hù)更容易,bug 修復(fù)不用到處 backport 了
  3. 開(kāi)發(fā)更靈活,HTTP/1 和 HTTP/2 可以一起改,不用擔(dān)心跨倉(cāng)庫(kù)的依賴(lài)問(wèn)題
  4. API 更統(tǒng)一,協(xié)議選擇、配置方式都變得清晰明了

預(yù)計(jì)這個(gè)改動(dòng)會(huì)在 Go 1.26 落地。

責(zé)任編輯:武曉燕 來(lái)源: 腦子進(jìn)煎魚(yú)了
相關(guān)推薦

2022-11-08 08:29:43

Goslog 庫(kù)工具

2025-09-08 09:10:18

Go網(wǎng)絡(luò)HTTP/3

2021-12-13 20:09:33

GoElasticsearJava

2023-05-05 08:51:18

Go語(yǔ)言泛型

2025-07-21 11:49:44

GoGit子目錄

2023-11-01 08:41:24

Go標(biāo)準(zhǔn)庫(kù)http

2023-12-04 08:46:40

Go標(biāo)準(zhǔn)庫(kù)

2014-01-14 09:10:53

GoHTTP內(nèi)存泄漏

2023-11-02 08:43:08

protocgo兼容

2025-07-01 07:53:47

2019-09-09 08:28:48

互聯(lián)網(wǎng)數(shù)據(jù)磁盤(pán)

2023-04-02 23:13:07

Go語(yǔ)言bufio

2025-04-28 05:00:00

2025-10-28 01:00:00

GoRecordertrace 格式

2022-03-15 08:10:05

Android二維碼掃描庫(kù)

2024-11-05 08:16:04

HTTP/3HTTP 2.0QUIC

2024-05-10 08:47:22

標(biāo)準(zhǔn)庫(kù)v2Go

2014-10-30 09:50:05

HTML5

2021-08-13 12:05:15

Goneturl

2019-08-28 16:38:49

finalJava編程語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)