Go http.Protocols 怎样让 Server 接收未加密 HTTP/2
来源:17golang原创
时间:2026-10-25 08:56:06 327浏览 收藏
如果 Go 服务端需要在同一个端口接收 HTTP/1 和未加密 HTTP/2,Go 1.24 起可以用 http.Protocols 明确写出协议集合,而不是依赖默认值猜测。关键配置是同时打开 HTTP1 与 UnencryptedHTTP2;后者就是通常所说的 h2c 接入边界。
官方文档:https://pkg.go.dev/net/http#Protocols
先把协议集合显式配置到 http.Server.Protocols,再确认客户端是否以未加密 HTTP/2 方式连接。它不等于 HTTPS,也不会替你配置证书或把普通 HTTP/1 请求自动升级成任意 HTTP/2 流程。
先确认 Protocols 的协议集合
http.Protocols 是一个协议集合,支持分别判断和设置 HTTP1、TLS 上的 HTTP2 与未加密连接上的 UnencryptedHTTP2。Server.Protocols 为 nil 时使用默认协议策略;如果要排障或灰度,最好改成显式集合,让配置意图可以从代码中直接读出来。

需要注意名称:HTTP2 表示 TLS 连接上的 HTTP/2,UnencryptedHTTP2 表示明文 TCP 上的 HTTP/2。两者是不同的成员,不能因为启用了一个就推断另一个也可用。
给 Server 配置未加密 HTTP/2
下面的配置让服务端保留 HTTP/1,同时允许未加密 HTTP/2。代码只展示配置关系,是否能接入还取决于客户端是否按对应的 HTTP/2 明文协议发起连接。
package main
import (
"log"
"net/http"
)
func main() {
protocols := new(http.Protocols)
protocols.SetHTTP1(true) // 保留普通 HTTP/1 接入
protocols.SetUnencryptedHTTP2(true) // 允许明文 TCP 上的 HTTP/2
server := &http.Server{
Addr: ":8080",
Handler: http.HandlerFunc(handle),
Protocols: protocols, // 显式声明服务端协议集合
}
// 示例只负责启动服务;生产环境还应接入自己的退出与日志策略。
log.Fatal(server.ListenAndServe())
}
func handle(w http.ResponseWriter, r *http.Request) {
// 用协议版本回显当前请求,便于接入方在日志中区分协议。
_, _ = w.Write([]byte(r.Proto))
}
这里的两个开关是独立的:只调用 SetUnencryptedHTTP2(true),并不会自动把 HTTP/1 纳入集合;只调用 SetHTTP1(true),也不会开放明文 HTTP/2。服务端需要哪些协议,就在同一个 Protocols 值上逐项声明。
区分 h2c 与 TLS HTTP/2
h2c 的核心特征是“HTTP/2 over cleartext”,也就是没有 TLS 的 HTTP/2。它适合内网、受控代理链或已经有独立网络保护的场景;如果客户端在公网或不可信网络中访问,不能把 h2c 当作 HTTPS 的替代品。
| 配置成员 | 连接形态 | 排障时要看什么 |
|---|---|---|
HTTP1 | 普通 HTTP/1 | 请求是否仍被旧客户端接受 |
HTTP2 | TLS 上的 HTTP/2 | TLS 与 ALPN 是否完成协商 |
UnencryptedHTTP2 | 明文 TCP 上的 HTTP/2 | 客户端是否使用 h2c 连接方式 |
尤其不要只在浏览器地址栏输入普通 http:// 地址,就认为客户端会自动使用未加密 HTTP/2。浏览器、代理和网关是否支持这种连接方式,要按实际链路单独确认;本文配置只定义 Go 服务端允许的协议集合。
上线前保留回滚配置
协议开关上线时,建议把“当前显式配置”和“回滚到默认策略”当成两个清楚的配置版本。若某个代理只会发 HTTP/1,保留 SetHTTP1(true) 可以避免把兼容性问题误判成服务不可用;若 h2c 链路没有经过受控网络,则应移除 SetUnencryptedHTTP2(true),回到只开放必要协议的方案。

可以按下面的顺序做配置复查:
- 确认服务端运行版本包含
http.Protocols,并明确记录目标协议。 - 确认
HTTP1、TLSHTTP2、UnencryptedHTTP2三者没有被混为一个“HTTP/2 开关”。 - 确认网关到服务端之间确实允许对应的明文 HTTP/2 连接方式。
- 保留一份移除 h2c 开关的回滚配置,出现协议协商异常时先恢复最小协议集合。
常见问题
只设置了 UnencryptedHTTP2,为什么旧客户端仍然连不上?
因为旧客户端可能只会发送 HTTP/1。若需要兼容它,应同时开启 HTTP1,并确认服务端入口没有被其他代理配置覆盖。
开启 HTTP2 是否就等于开启 h2c?
不是。HTTP2 对应 TLS 上的 HTTP/2,UnencryptedHTTP2 才对应明文 HTTP/2;根据链路安全边界分别选择。
为什么不直接依赖 Protocols 的零值?
零值适合默认场景,但排查协议兼容性时不够直观。显式集合能把服务端到底接受什么写进代码和配置记录,回滚时也更容易对照。
总结:把 Server.Protocols 当作协议白名单来维护,HTTP/1、TLS HTTP/2 和 h2c 分别判断;需要未加密 HTTP/2 时显式调用 SetUnencryptedHTTP2(true),并为网络边界和回滚路径留下记录。
-
Golang · Go教程 | 4个月前 | Go教程 · 后端工程 · Golang实战 · net/http · 服务治理 · golang shutdown Go net/http HTTP服务 优雅关闭 SIGTERM 生产实践135 收藏
-
Golang · Go教程 | 4个月前 | web安全 · Go教程 · 后端工程 · Golang实战 · net/http · golang 安全 Go net/http HTTP服务 csrf Go1.25 CrossOriginProtection183 收藏
-
Golang · Go教程 | 3个月前 | 跨域 · cors · Go教程 · net/http · 跨域 Access-Control-Allow-Origin 预检请求 Options Go教程 Go CORS275 收藏
-
Golang · Go教程 | 3个月前 | golang · HTTP · 安全 · Go教程 · net/http · net/http 请求超时 MaxBytesReader Go HTTP 请求体限制 内存防护173 收藏
-
395 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习