是,Go 1.8+ 启动 HTTPS 服务(如用 http.ListenAndServeTLS 或配置 TLSConfig)即自动启用 HTTP/2,无需额外导入或调用配置函数;纯 HTTP 则永远为 HTTP/1.1。

Go 启动 HTTPS 服务就自动启用 HTTP/2
只要用 http.ListenAndServeTLS 或配置了 TLSConfig 的 http.Server,Go 1.8+ 就会自动协商 HTTP/2 —— 不需要 import golang.org/x/net/http2,也不用调 http2.ConfigureServer。这是默认行为,不是可选功能。
常见错误是手动往 TLSConfig.NextProtos 里塞 ["h2"],其实多余;Go 已内置 ALPN 协商支持,加了反而可能干扰默认逻辑。
- 正确做法:直接调
http.ListenAndServeTLS(":443", "cert.pem", "key.pem") - 自定义 server 时,哪怕
TLSConfig是空结构体也要显式设置:&http.Server{Addr: ":443", TLSConfig: &tls.Config{}} - 纯
http.ListenAndServe永远走 HTTP/1.1,HTTP/2 不支持明文
确认 HTTP/2 真正在跑,别信日志信连接
代码里写了 TLS ≠ 实际用了 HTTP/2。浏览器 DevTools 的 Protocol 列才是黄金标准:Network 面板右键表头勾选 Protocol,主 HTML 响应行显示 h2 才算成功。
curl 命令验证更底层:curl -v --http2 https://localhost:443,重点看三处:
立即学习“go语言免费学习笔记(深入)”;
- 输出里有
ALPN, offering h2和SSL connection using TLSv1.3 - 响应行是
HTTP/2 200,不是HTTP/1.1 200 - 没有
Failed to negotiate ALPN类报错
服务端也可加判断:if r.Proto == "HTTP/2.0"(注意是 HTTP/2.0,不是 HTTP/2)
反向代理后端必须透传 TLS,否则 HTTP/2 降级
Nginx / Caddy 作为前置代理时,如果只做 TLS 终止再以 HTTP/1.1 转发,Go 后端看到的仍是 r.Proto == "HTTP/1.1",HTTP/2 彻底失效。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
要透传 HTTP/2,Nginx 必须开启 HTTP/2 代理并严格配置:
proxy_http_version 2.0proxy_ssl_protocols TLSv1.2 TLSv1.3proxy_ssl_server_name on
Caddy 默认支持,但需确保 upstream 地址带 https:// 前缀,且证书可信(或配置 insecure_skip_verify)
Server Push 已弃用,用 Link 头替代
Go 1.23 起 http.Pusher 接口被移除,所有基于它的 Server Push 代码会编译失败。这不是 bug,是明确弃用。
现代替代方案是响应头 Link 预加载:
w.Header().Set("Link", `<style.css>; rel=preload; as=style`, `<app.js>; rel=preload; as=script`)
注意点:
- 只对未缓存资源有效,已缓存的浏览器会忽略
- 推送体积建议 ≤100KB,过大反而拖慢主文档渲染
- 优先级靠浏览器自主调度,不保证执行顺序
真正容易被忽略的是:HTTP/2 性能提升高度依赖 TLS 握手速度和 TCP 连接复用。用自签名证书测试时,InsecureSkipVerify: true 只解决信任问题,不解决握手延迟——生产环境务必用有效证书 + OCSP stapling + TLS 1.3。

















