一、首先什么是HTTP3?
虽然 HTTP/2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支撑的 TCP 协议造成的。
上文提到 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况,那就会导致 HTTP/2 的表现情况反倒不如 HTTP/1 了。
因为在出现丢包的情况下,整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。但是对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
那么可能就会有人考虑到去修改 TCP 协议,其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长,已经充斥在各种设备中,并且这个协议是由操作系统实现的,更新起来不大现实。
基于这个原因,Google 就更起炉灶搞了一个基于 UDP 协议的 QUIC 协议,并且使用在了 HTTP/3 上,HTTP/3 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。
QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能。
参考:读懂 HTTP/2 及 HTTP/3 特性
二、用go语言实现HTTP3
package main
import (
"compress/flate"
"compress/gzip"
"flag"
"fmt"
"io"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"/itchio/go-brotli/enc"
"/lucas-clemente/quic-go/http3"
)
type compressResponseWriter struct {
}
func (w compressResponseWriter) Write(b []byte) (int, error) {
return (b)
}
func (w compressResponseWriter) WriteHeader(code int) {
().Del("Content-Length")
(code)
}
func gzipHandler(fn , w , r *) {
().Set("Content-Encoding", "gzip")
gz, err := (w, )
if err != nil {
("Error closing gzip: %+v\n", err)
}
defer func() {
err := ()
if err != nil {
("Error closing gzip: %+v\n", err)
}
}()
gzr := compressResponseWriter{Writer: gz, ResponseWriter: w}
fn(gzr, r)
}
func deflateHandler(fn , w , r *) {
().Set("Content-Encoding", "deflate")
df, err := (w, )
if err != nil {
("Error closing deflate: %+v\n", err)
}
defer func() {
err := ()
if err != nil {
("Error closing deflate: %+v\n", err)
}
}()
dfr := compressResponseWriter{Writer: df, ResponseWriter: w}
fn(dfr, r)
}
func brotliHandler(fn , w , r *) {
().Set("Content-Encoding", "br")
op := &{
Quality: 4,
LGWin: 10,
}
br := (w, op)
defer func() {
err := ()
if err != nil {
("Error closing brotli: %+v\n", err)
}
}()
brr := compressResponseWriter{Writer: br, ResponseWriter: w}
fn(brr, r)
}
type handler struct {
enableCompress bool
}
func (h *handler) makeCompressionHandler(fn ) {
return func(w , r *) {
if {
().Set("Vary", "Assept-Encoding")
if (("Accept-Encoding"), "br") {
brotliHandler(fn, w, r)
return
} else if (("Accept-Encoding"), "gzip") {
gzipHandler(fn, w, r)
return
} else if (("Accept-Encoding"), "deflate") {
deflateHandler(fn, w, r)
return
}
}
fn(w, r)
}
}
func reverseProxy(backEndUrl string) func(, *) {
url, err := (backEndUrl)
if err != nil {
panic(err)
}
proxy := (url)
return
}
func main() {
var (
bg = ("b", "http://localhost:9000", "background")
port = ("p", 8080, "front port")
useHttp3 = ("enable_http3", false, "use http3")
certPath = ("c", "", "cert file path")
keyPath = ("k", "", "key file path")
enableCompress = ("enable_compress", false, "enable compress")
)
()
h := handler{
enableCompress: *enableCompress,
}
proxyServer := {
Addr: ("0.0.0.0:%d", *port),
Handler: (reverseProxy(*bg)),
}
if *useHttp3 {
("http3")
if err := (, *certPath, *keyPath, ); err != nil {
(err)
}
} else {
("http")
if err := (); err != nil {
(err)
}
}
}