Golang用Proto文件同時(shí)生成gRPC和HTTP
大家好,我是Z哥。
做技術(shù)的都知道,程序之間的通訊,常用的方式有兩種,RPC 和 HTTP。普遍的共識(shí)是系統(tǒng)內(nèi)部的各個(gè)子系統(tǒng)之間的通訊用 RPC,與外部系統(tǒng)之間的通訊用 HTTP。
為了避免需要分別編寫(xiě)兩套契約文件來(lái)生成兩套 API(.proto 和 .api),如果能夠根據(jù)同一份契約文件生成兩套 API 的代碼就太棒了。
Z哥目前所在的公司,rpc 使用的框架是 gRPC,所以自然先想得是,是否能夠根據(jù)一份 proto 文件,同時(shí)生成 gRPC 和 HTTP 的 stub 代碼呢。
網(wǎng)上很快就找到了一個(gè)符合要求的框架。相信不少 gopher 們應(yīng)該也聽(tīng)說(shuō)過(guò)或者正在使用。
https://github.com/grpc-ecosystem/grpc-gateway
框架的原理用一張圖即可表達(dá)。
通過(guò)一份 proto 文件,在生成 gRPC 代碼的同時(shí)生成一個(gè)基于 HTTP1.1 + JSON 的反向代理 gateway,如此一來(lái),既可以通過(guò) gRPC 的方式直接調(diào)用實(shí)際的 server ,也可以通過(guò)反向代理中轉(zhuǎn)一次來(lái)訪問(wèn) server。
具體的使用方式看 github 上的官方教程即可,Z 哥和你主要聊一下其中可能會(huì)遇到的卡點(diǎn)。畢竟國(guó)內(nèi)的網(wǎng)絡(luò)情況你懂的,有些操作可能會(huì)遇到一些困難。
1.不會(huì)科學(xué)上網(wǎng)不要用buf
教程里提供了兩種來(lái)操作,一種是通過(guò)基礎(chǔ)工具 protoc 來(lái)操作,另一種是通過(guò)一個(gè)基于 protoc 封裝的工具 buf 來(lái)操作。protoc 可以基于 go mod 來(lái)安裝,鑒于 go mod 還有國(guó)內(nèi)的鏡像站點(diǎn)可以解決訪問(wèn)的困難,建議不會(huì)科學(xué)上網(wǎng)的小伙伴通過(guò) protoc 來(lái)操作,因?yàn)槟銢](méi)辦法成功安裝 buf。
2.手動(dòng)下載 googleapis 的repo
然后,當(dāng)你定義 gateway 的時(shí)候,需要引入一些 google 的 packages,怎么辦呢?直接去 github 上下載,具體地址是:
https://github.com/googleapis/googleapis
如果可以的話,建議把整個(gè)倉(cāng)庫(kù)都下載下來(lái),否則就單獨(dú)下載教程里提到的4個(gè)文件即可。
特別要注意的是,在 googleapis/google/目錄下缺少的 protobuf 相關(guān)文件需要到下面的 repo 里去下載,并且放到 googleapis/google/目錄下。
https://github.com/protocolbuffers/protobuf/tree/main/src/google/protobuf
3.protoc -I 指定查找目錄
官方教程里的 protoc -I . 只會(huì)查找當(dāng)前命令執(zhí)行所在目錄的范圍,所以如果你下載的 googlesapi 不存放在當(dāng)前目錄下,則需要增加額外信息指定一下查找目錄。
指定的方式是再增加一個(gè) -I,命令如下(其中第二行就是新增的用于查找 google packages 的目錄):
protoc -I ./ \
-I $GOPATH/src/googleapis\
--grpc-gateway_out ./gen/go \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
--grpc-gateway_opt generate_unbound_methods=true \
your/service/v1/your_service.proto
如果還有其它目錄需要查找,那么繼續(xù)增加 -I 即可。
好了需要注意的點(diǎn)就是以上3個(gè),官方教程中提到的三個(gè)命令可以一起執(zhí)行,這樣便可同時(shí)生成 gRPC server、gateway 和 swagger.json :
protoc -I ./ \
-I $GOPATH/src/googleapis\
--go_out ./gen/go/ --go_opt paths=source_relative \
--go-grpc_out ./gen/go/ --go-grpc_opt paths=source_relative \
--grpc-gateway_out ./gen/go/ \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
--grpc-gateway_opt generate_unbound_methods=true \
--openapiv2_out . --openapiv2_opt logtostderr=true \
your/service/v1/your_service.proto
關(guān)于一些gRPC-Gateway的其它用法可以參考:
https://grpc-ecosystem.github.io/grpc-gateway/
好了,這篇呢,Z哥和你分享了如何用一份 proto 文件同時(shí)生成 gRPC 和 HTTP 的 Stub 代碼以及 Swagger 文檔。
如此不但可以提高效率,還可以避免維護(hù)兩份不同的契約文件所帶來(lái)不一致風(fēng)險(xiǎn),希望對(duì)你有所幫助。