From 89faaacc66b92c4bbb9730cc19c0cb12720dca04 Mon Sep 17 00:00:00 2001 From: chaoranz758 <2715584135@qq.com> Date: Sat, 29 Jul 2023 21:33:25 +0800 Subject: [PATCH 1/4] docs: add document http3 --- .../tutorials/basic-feature/protocol/http3.md | 211 ++++++++++++++++++ .../tutorials/basic-feature/protocol/tls.md | 2 +- .../basic-feature/protocol/websocket.md | 2 +- 3 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md new file mode 100644 index 0000000000..bfcae45c34 --- /dev/null +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -0,0 +1,211 @@ +--- +title: "HTTP3" +date: 2023-07-29 +weight: 3 +description: > + +--- + +QUIC 协议是一种传输层网络协议,提供与 TLS/SSL 相当的安全性,同时具有更低的连接和传输延迟。QUIC 目前主要应用于 HTTP 协议,HTTP-over-QUIC 协议即为 HTTP/3,是 HTTP 协议的第三个正式版本。 + +HTTP3 基于 [quic-go](https://github.com/quic-go/quic-go) 实现,[实现链接](https://github.com/hertz-contrib/http3)。 + +## 安装 + +```go +go get github.com/hertz-contrib/http3 +``` + +>注意:go 版本需大于等于 1.19。 + +## 示例代码 + +### 服务端 + +>注意:QUIC 协议依赖于 TLS 协议,因此需要提供 TLS配置。 + +```go +package main + +import ( + "context" + "fmt" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/network/netpoll" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/cloudwego/hertz/pkg/protocol/suite" + "github.com/hertz-contrib/http3/network/quic-go" + "github.com/hertz-contrib/http3/network/quic-go/testdata" + http3 "github.com/hertz-contrib/http3/server/quic-go" + "github.com/hertz-contrib/http3/server/quic-go/factory" +) + +type Test struct { + A string + B string +} + +func main() { + run() +} + +func run() { + h := server.New(server.WithALPN(true), server.WithTLS(testdata.GetTLSConfig()), server.WithTransport(quic.NewTransporter), server.WithAltTransport(netpoll.NewTransporter), server.WithHostPorts("127.0.0.1:8080")) + h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) + + h.GET("/demo/tile", func(c context.Context, ctx *app.RequestContext) { + // Small 40x40 png + ctx.Write([]byte{ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00, + 0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb, + 0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18, + 0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + }) + }) + + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) + }) + + h.GET("/struct", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, &Test{ + A: "aaa", + B: "bbb", + }) + }) + + v1 := h.Group("/v1") + { + v1.GET("/hello/:name", func(c context.Context, ctx *app.RequestContext) { + fmt.Fprintf(ctx, "Hi %s, this is the response from Hertz.\n", ctx.Param("name")) + }) + } + + h.Spin() +} +``` + +### 客户端 + +Hertz-HTTP3 目前没有提供客户端的实现,但 [服务端](#服务端) 示例代码的 TLS 配置直接拷贝于 [quic-go](https://github.com/quic-go/quic-go),因此可以直接使用 [quic-go](https://github.com/quic-go/quic-go) 中的 [客户端示例代码](https://github.com/quic-go/quic-go/blob/master/example/client/main.go) 。 + +示例代码: + +```go +package main + +import ( + "bufio" + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "sync" + + "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/http3" + "github.com/quic-go/quic-go/internal/testdata" + "github.com/quic-go/quic-go/internal/utils" + "github.com/quic-go/quic-go/logging" + "github.com/quic-go/quic-go/qlog" +) + +func main() { + verbose := flag.Bool("v", false, "verbose") + quiet := flag.Bool("q", false, "don't print the data") + keyLogFile := flag.String("keylog", "", "key log file") + insecure := flag.Bool("insecure", false, "skip certificate verification") + enableQlog := flag.Bool("qlog", false, "output a qlog (in the same directory)") + flag.Parse() + urls := flag.Args() + + logger := utils.DefaultLogger + + if *verbose { + logger.SetLogLevel(utils.LogLevelDebug) + } else { + logger.SetLogLevel(utils.LogLevelInfo) + } + logger.SetLogTimeFormat("") + + var keyLog io.Writer + if len(*keyLogFile) > 0 { + f, err := os.Create(*keyLogFile) + if err != nil { + log.Fatal(err) + } + defer f.Close() + keyLog = f + } + + pool, err := x509.SystemCertPool() + if err != nil { + log.Fatal(err) + } + testdata.AddRootCA(pool) + + var qconf quic.Config + if *enableQlog { + qconf.Tracer = func(ctx context.Context, p logging.Perspective, connID quic.ConnectionID) logging.ConnectionTracer { + filename := fmt.Sprintf("client_%x.qlog", connID) + f, err := os.Create(filename) + if err != nil { + log.Fatal(err) + } + log.Printf("Creating qlog file %s.\n", filename) + return qlog.NewConnectionTracer(utils.NewBufferedWriteCloser(bufio.NewWriter(f), f), p, connID) + } + } + roundTripper := &http3.RoundTripper{ + TLSClientConfig: &tls.Config{ + RootCAs: pool, + InsecureSkipVerify: *insecure, + KeyLogWriter: keyLog, + }, + QuicConfig: &qconf, + } + defer roundTripper.Close() + hclient := &http.Client{ + Transport: roundTripper, + } + + var wg sync.WaitGroup + wg.Add(len(urls)) + for _, addr := range urls { + logger.Infof("GET %s", addr) + go func(addr string) { + rsp, err := hclient.Get(addr) + if err != nil { + log.Fatal(err) + } + logger.Infof("Got response for %s: %#v", addr, rsp) + + body := &bytes.Buffer{} + _, err = io.Copy(body, rsp.Body) + if err != nil { + log.Fatal(err) + } + if *quiet { + logger.Infof("Response Body: %d bytes", body.Len()) + } else { + logger.Infof("Response Body:") + logger.Infof("%s", body.Bytes()) + } + wg.Done() + }(addr) + } + wg.Wait() +} +``` \ No newline at end of file diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md index b3e618b50d..886d510660 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md @@ -1,7 +1,7 @@ --- title: "TLS" date: 2022-11-06 -weight: 4 +weight: 5 description: > --- diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md index 48c0b18249..63274a8c34 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md @@ -1,7 +1,7 @@ --- title: "Websocket" date: 2022-09-13 -weight: 3 +weight: 4 description: > --- From 1c27fd144873c0c714b12879485bad05a0d00655 Mon Sep 17 00:00:00 2001 From: chaoranz758 <2715584135@qq.com> Date: Mon, 31 Jul 2023 22:11:05 +0800 Subject: [PATCH 2/4] docs: supplement document http3 --- .../tutorials/basic-feature/protocol/http3.md | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md index bfcae45c34..51fb0fc444 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -18,6 +18,33 @@ go get github.com/hertz-contrib/http3 >注意:go 版本需大于等于 1.19。 +## 网络层与协议层注册 + +### 网络层注册 + +```go +server.New(server.WithTransport(quic.NewTransporter)) +``` + +### 协议层注册 + +```go +server.New(server.WithTransport(quic.NewTransporter)) +h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) +``` + +## 配置说明 + +### 服务端 + +| 配置 | 说明 | +| :----------------- | -------------------------------------------- | +| WithTransport | 设置 HTTP3 实现的网络库 `quic.NewTransporter` | +| WithAltTransport | 设置备用网络库 `netpoll` 或 `go net`,适用于同时在 TCP 和 QUIC 监听的场景 | +| WithALPN | 设置是否启用 ALPN | +| WithTLS | 设置 TLS 配置 | +| WithHostPorts | 设置开启服务的域名和端口号 | + ## 示例代码 ### 服务端 @@ -208,4 +235,6 @@ func main() { } wg.Wait() } -``` \ No newline at end of file +``` + + From f9a9b3f95924df5a39cbf2355dea7cab3c1330c5 Mon Sep 17 00:00:00 2001 From: chaoranz758 <2715584135@qq.com> Date: Tue, 1 Aug 2023 19:51:00 +0800 Subject: [PATCH 3/4] docs: add english document http3 --- .../tutorials/basic-feature/protocol/http3.md | 238 ++++++++++++++++++ .../tutorials/basic-feature/protocol/tls.md | 2 +- .../basic-feature/protocol/websocket.md | 2 +- .../tutorials/basic-feature/protocol/http3.md | 2 - 4 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md new file mode 100644 index 0000000000..58ddb26ac7 --- /dev/null +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -0,0 +1,238 @@ +--- +title: "HTTP3" +date: 2023-07-29 +weight: 3 +description: > + +--- + +`QUIC` protocol is a transport layer network protocol that provides security equivalent to TLS/SSL, while also having lower connection and transmission latency. `QUIC` is currently mainly used in the `HTTP` protocol, which is known as `HTTP/3` and is the third official version of the `HTTP` protocol. + +`HTTP3` implementation based [quic-go](https://github.com/quic-go/quic-go), [Implementation Link](https://github.com/hertz-contrib/http3). + +## Install + +```go +go get github.com/hertz-contrib/http3 +``` + +>Note: The go version must be greater than or equal to 1.19. + +## Network Layer and Protocol Layer Registration + +### Network Layer Registration + +```go +server.New(server.WithTransport(quic.NewTransporter)) +``` + +### Protocol Layer Registration + +```go +server.New(server.WithTransport(quic.NewTransporter)) +h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) +``` + +## Config Description + +### Server + +| **Option** | **Description** | +| :----------------- | -------------------------------------------- | +| WithTransport | Set the network layer implementation | +| WithAltTransport | Set the alternative network layer implementation. The AltTransporter will be used for parallel listening - both in `TCP` and `QUIC` | +| WithALPN | Set whether to enable `ALPN` | +| WithTLS | Set `TLS` Config | +| WithHostPorts | Set the host and port for starting the service | + +## Sample Code + +### Server + +>Note: The `QUIC` protocol relies on the `TLS` protocol, so `TLS` configuration needs to be provided. + +```go +package main + +import ( + "context" + "fmt" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/network/netpoll" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/cloudwego/hertz/pkg/protocol/suite" + "github.com/hertz-contrib/http3/network/quic-go" + "github.com/hertz-contrib/http3/network/quic-go/testdata" + http3 "github.com/hertz-contrib/http3/server/quic-go" + "github.com/hertz-contrib/http3/server/quic-go/factory" +) + +type Test struct { + A string + B string +} + +func main() { + run() +} + +func run() { + h := server.New(server.WithALPN(true), server.WithTLS(testdata.GetTLSConfig()), server.WithTransport(quic.NewTransporter), server.WithAltTransport(netpoll.NewTransporter), server.WithHostPorts("127.0.0.1:8080")) + h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) + + h.GET("/demo/tile", func(c context.Context, ctx *app.RequestContext) { + // Small 40x40 png + ctx.Write([]byte{ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00, + 0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb, + 0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18, + 0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + }) + }) + + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) + }) + + h.GET("/struct", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, &Test{ + A: "aaa", + B: "bbb", + }) + }) + + v1 := h.Group("/v1") + { + v1.GET("/hello/:name", func(c context.Context, ctx *app.RequestContext) { + fmt.Fprintf(ctx, "Hi %s, this is the response from Hertz.\n", ctx.Param("name")) + }) + } + + h.Spin() +} +``` + +### Client + +Hertz-HTTP3 currently does not provide a client implementation, but the `TLS` configuration of the [server](#server) sample code is directly copied to [quic-go](https://github.com/quic-go/quic-go). Therefore, you can directly use the [Client Example Code](https://github.com/quic-go/quic-go/blob/master/example/client/main.go) in [quic-go](https://github.com/quic-go/quic-go). + +```go +package main + +import ( + "bufio" + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "sync" + + "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/http3" + "github.com/quic-go/quic-go/internal/testdata" + "github.com/quic-go/quic-go/internal/utils" + "github.com/quic-go/quic-go/logging" + "github.com/quic-go/quic-go/qlog" +) + +func main() { + verbose := flag.Bool("v", false, "verbose") + quiet := flag.Bool("q", false, "don't print the data") + keyLogFile := flag.String("keylog", "", "key log file") + insecure := flag.Bool("insecure", false, "skip certificate verification") + enableQlog := flag.Bool("qlog", false, "output a qlog (in the same directory)") + flag.Parse() + urls := flag.Args() + + logger := utils.DefaultLogger + + if *verbose { + logger.SetLogLevel(utils.LogLevelDebug) + } else { + logger.SetLogLevel(utils.LogLevelInfo) + } + logger.SetLogTimeFormat("") + + var keyLog io.Writer + if len(*keyLogFile) > 0 { + f, err := os.Create(*keyLogFile) + if err != nil { + log.Fatal(err) + } + defer f.Close() + keyLog = f + } + + pool, err := x509.SystemCertPool() + if err != nil { + log.Fatal(err) + } + testdata.AddRootCA(pool) + + var qconf quic.Config + if *enableQlog { + qconf.Tracer = func(ctx context.Context, p logging.Perspective, connID quic.ConnectionID) logging.ConnectionTracer { + filename := fmt.Sprintf("client_%x.qlog", connID) + f, err := os.Create(filename) + if err != nil { + log.Fatal(err) + } + log.Printf("Creating qlog file %s.\n", filename) + return qlog.NewConnectionTracer(utils.NewBufferedWriteCloser(bufio.NewWriter(f), f), p, connID) + } + } + roundTripper := &http3.RoundTripper{ + TLSClientConfig: &tls.Config{ + RootCAs: pool, + InsecureSkipVerify: *insecure, + KeyLogWriter: keyLog, + }, + QuicConfig: &qconf, + } + defer roundTripper.Close() + hclient := &http.Client{ + Transport: roundTripper, + } + + var wg sync.WaitGroup + wg.Add(len(urls)) + for _, addr := range urls { + logger.Infof("GET %s", addr) + go func(addr string) { + rsp, err := hclient.Get(addr) + if err != nil { + log.Fatal(err) + } + logger.Infof("Got response for %s: %#v", addr, rsp) + + body := &bytes.Buffer{} + _, err = io.Copy(body, rsp.Body) + if err != nil { + log.Fatal(err) + } + if *quiet { + logger.Infof("Response Body: %d bytes", body.Len()) + } else { + logger.Infof("Response Body:") + logger.Infof("%s", body.Bytes()) + } + wg.Done() + }(addr) + } + wg.Wait() +} +``` + + diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md index ccc8bb4a77..5bf625ebaa 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md @@ -1,7 +1,7 @@ --- title: "TLS" date: 2022-11-06 -weight: 4 +weight: 5 description: > --- diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md index 214bbc1ca1..53cc5bca4a 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md @@ -1,7 +1,7 @@ --- title: "Websocket" date: 2022-09-13 -weight: 3 +weight: 4 description: > --- diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md index 51fb0fc444..3a3a4325d0 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -122,8 +122,6 @@ func run() { Hertz-HTTP3 目前没有提供客户端的实现,但 [服务端](#服务端) 示例代码的 TLS 配置直接拷贝于 [quic-go](https://github.com/quic-go/quic-go),因此可以直接使用 [quic-go](https://github.com/quic-go/quic-go) 中的 [客户端示例代码](https://github.com/quic-go/quic-go/blob/master/example/client/main.go) 。 -示例代码: - ```go package main From 561570e615a29d45d9d66f010ac5eb1b43ed53c0 Mon Sep 17 00:00:00 2001 From: kinggo Date: Wed, 2 Aug 2023 11:23:05 +0800 Subject: [PATCH 4/4] docs: fix comment --- .../en/docs/hertz/tutorials/basic-feature/protocol/http3.md | 4 ++-- .../zh/docs/hertz/tutorials/basic-feature/protocol/http3.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md index 58ddb26ac7..c165c214d5 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -6,9 +6,9 @@ description: > --- -`QUIC` protocol is a transport layer network protocol that provides security equivalent to TLS/SSL, while also having lower connection and transmission latency. `QUIC` is currently mainly used in the `HTTP` protocol, which is known as `HTTP/3` and is the third official version of the `HTTP` protocol. +QUIC protocol is a transport layer network protocol that provides security equivalent to TLS/SSL, while also having lower connection and transmission latency. `QUIC` is currently mainly used in the `HTTP` protocol, which is known as `HTTP/3` and is the third official version of the `HTTP` protocol. -`HTTP3` implementation based [quic-go](https://github.com/quic-go/quic-go), [Implementation Link](https://github.com/hertz-contrib/http3). +Hertz-HTTP3 implementation based [quic-go](https://github.com/quic-go/quic-go), [Implementation Link](https://github.com/hertz-contrib/http3). ## Install diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md index 3a3a4325d0..a3861ddc34 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -8,7 +8,7 @@ description: > QUIC 协议是一种传输层网络协议,提供与 TLS/SSL 相当的安全性,同时具有更低的连接和传输延迟。QUIC 目前主要应用于 HTTP 协议,HTTP-over-QUIC 协议即为 HTTP/3,是 HTTP 协议的第三个正式版本。 -HTTP3 基于 [quic-go](https://github.com/quic-go/quic-go) 实现,[实现链接](https://github.com/hertz-contrib/http3)。 +Hertz-HTTP3 基于 [quic-go](https://github.com/quic-go/quic-go) 实现,[实现链接](https://github.com/hertz-contrib/http3)。 ## 安装 @@ -49,7 +49,7 @@ h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) ### 服务端 ->注意:QUIC 协议依赖于 TLS 协议,因此需要提供 TLS配置。 +>注意:QUIC 协议依赖于 TLS 协议,因此需要提供 TLS 配置。 ```go package main