go实现HTTP3

时间:2025-03-02 09:25:49

一、首先什么是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)
		}
	}
}