内容简介:如果你以前有涉猎过 gRPC+gRPC Gateway 这两个组件,你肯定会遇到这个问题,就是因为
gRPC+gRPC Gateway 能不能不用证书?
如果你以前有涉猎过 gRPC+gRPC Gateway 这两个组件,你肯定会遇到这个问题,就是 “为什么非得开 TLS,才能够实现同端口双流量,能不能不开?” 又或是 “我不想用证书就实现这些功能,行不行?” 。我被无数的人问过无数次这些问题,也说服过很多人,但说服归说服,不代表放弃。前年不行,不代表今年不行,在今天我希望分享来龙去脉和具体的实现方式给你。
过去
为什么 h2 不行
因为 net/http2
仅支持 "h2" 标识,而 "h2" 标识 HTTP/2 必须使用传输层安全性(TLS)的协议,此标识符用于 TLS 应用层协议协商字段以及识别 HTTP/2 over TLS。
简单来讲,也就 net/http2
必须使用 TLS 来交互。通俗来讲就要用证书,那么理所当然,也就无法支持非 TLS 的情况了。
寻找 h2c
那这条路不行,我们再想想别的路?那就是 HTTP/2 规范中的 "h2c" 标识了,"h2c" 标识允许通过明文 TCP 运行 HTTP/2 的协议,此标识符用于 HTTP/1.1 升级标头字段以及标识 HTTP/2 over TCP。
但是这条路,早在 2015 年就已经有在 issue 中进行讨论,当时 @bradfitz 明确表示 “不打算支持 h2c,对仅支持 TLS 的情况非常满意,一年后再问我一次”,原文回复如下:
We do not plan to support h2c. I don't want to receive bug reports from users who get bitten by transparent proxies messing with h2c. Also, until there's widespread browser support, it's not interesting. I am also not interested in being the chicken or the egg to get browser support going. I'm very happy with the TLS-only situation, and things like https://LetsEncrypt.org/ will make TLS much easier (and automatic) soon.
Ask me again in one year.
琢磨其他方式
使用 cmux
基于多路复用器 soheilhy/cmux 的另类实现 Stoakes/grpc-gateway-example 。若对 cmux
的实现方式感兴趣,还可以看看 《Golang: Run multiple services on one port》 。
使用第三方 h2
这种属于自己实现了 h2c 的逻辑,以此达到效果。
现在
经过社区的不断讨论,最后在 2018 年 6 月,代表 "h2c" 标志的 golang.org/x/net/http2/h2c
标准库正式合并进来,自此我们就可以使用官方标准库(h2c),这个标准库实现了 HTTP/2 的未加密模式,因此我们就可以利用该标准库在同个端口上既提供 HTTP/1.1 又提供 HTTP/2 的功能了。
使用标准库 h2c
import ( ... "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" "google.golang.org/grpc" "github.com/grpc-ecosystem/grpc-gateway/runtime" pb "github.com/EDDYCJY/go-grpc-example/proto" ) ... func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler { return h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") { grpcServer.ServeHTTP(w, r) } else { otherHandler.ServeHTTP(w, r) } }), &http2.Server{}) } func main() { server := grpc.NewServer() pb.RegisterSearchServiceServer(server, &SearchService{}) mux := http.NewServeMux() gwmux := runtime.NewServeMux() dopts := []grpc.DialOption{grpc.WithInsecure()} err := pb.RegisterSearchServiceHandlerFromEndpoint(context.Background(), gwmux, "localhost:"+PORT, dopts) ... mux.Handle("/", gwmux) http.ListenAndServe(":"+PORT, grpcHandlerFunc(server, mux)) }
我们可以看到关键之处在于调用了 h2c.NewHandler
方法进行了特殊处理, h2c.NewHandler
会返回一个 http.handler
,主要的内部逻辑是拦截了所有 h2c
流量,然后根据不同的请求流量类型将其劫持并重定向到相应的 Hander
中去处理。
验证
HTTP/1.1
$ curl -X GET 'http://127.0.0.1:9005/search?request=EDDYCJY' {"response":"EDDYCJY"}
HTTP/2(gRPC)
... func main() { conn, err := grpc.Dial(":"+PORT, grpc.WithInsecure()) ... client := pb.NewSearchServiceClient(conn) resp, err := client.Search(context.Background(), &pb.SearchRequest{ Request: "gRPC", }) }
输出结果:
$ go run main.go 2019/06/21 20:04:09 resp: gRPC h2c Server
总结
在本文中我介绍了大致的前因后果,且介绍了几种解决方法,我建议你选择官方的 h2c
标准库去实现这个功能,也简单。在最后,不管你是否曾经为这个问题烦恼过许久,又或者正在纠结,都希望这篇文章能够帮到你。
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Algorithm Design Manual
Steve S. Skiena / Springer / 1998-8-1 / GBP 53.91
Contents u Techniques u Introduction to Algorithms u Correctness and Efficiency u Correctness u Efficiency u Expressing Algorithms u Keeping Score u The RAM Model of Computatio......一起来看看 《The Algorithm Design Manual》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
RGB HSV 转换
RGB HSV 互转工具