Go gRPC进阶教程gRPC转换HTTP
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《Go gRPC进阶教程gRPC转换HTTP》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!
gRPC转成HTTP
编写和编译proto
1.编写simple.proto
syntax = "proto3";
package proto;
import "github.com/mwitkow/go-proto-validators/validator.proto";
import "go-grpc-example/10-grpc-gateway/proto/google/api/annotations.proto";
message InnerMessage {
// some_integer can only be in range (1, 100).
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
// some_float can only be in range (0;1).
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
}
message OuterMessage {
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
}
service Simple{
rpc Route (InnerMessage) returns (OuterMessage){
option (google.api.http) ={
post:"/v1/example/route"
body:"*"
};
}
}
可以看到,proto变化不大,只是添加了API的路由路径
option (google.api.http) ={
post:"/v1/example/route"
body:"*"
};
2.编译simple.proto
simple.proto文件引用了google/api/annotations.proto,先要把它编译了。我这里是把google/文件夹直接复制到项目中的proto/目录中进行编译。发现annotations.proto引用了google/api/http.proto,那把它也编译了。
进入annotations.proto所在目录,编译:
protoc --go_out=plugins=grpc:./ ./http.proto protoc --go_out=plugins=grpc:./ ./annotations.proto
进入simple.proto所在目录,编译:
#生成simple.validator.pb.go和simple.pb.go protoc --govalidators_out=. --go_out=plugins=grpc:./ ./simple.proto #生成simple.pb.gw.go protoc --grpc-gateway_out=logtostderr=true:./ ./simple.proto
以上完成proto编译,接着修改服务端代码。
服务端代码修改
1.server/文件夹下新建gateway/目录,然后在里面新建gateway.go文件
package gateway
import (
"context"
"crypto/tls"
"io/ioutil"
"log"
"net/http"
"strings"
pb "go-grpc-example/10-grpc-gateway/proto"
"go-grpc-example/10-grpc-gateway/server/swagger"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
)
// ProvideHTTP 把gRPC服务转成HTTP服务,让gRPC同时支持HTTP
func ProvideHTTP(endpoint string, grpcServer *grpc.Server) *http.Server {
ctx := context.Background()
//获取证书
creds, err := credentials.NewClientTLSFromFile("../tls/server.pem", "go-grpc-example")
if err != nil {
log.Fatalf("Failed to create TLS credentials %v", err)
}
//添加证书
dopts := []grpc.DialOption{grpc.WithTransportCredentials(creds)}
//新建gwmux,它是grpc-gateway的请求复用器。它将http请求与模式匹配,并调用相应的处理程序。
gwmux := runtime.NewServeMux()
//将服务的http处理程序注册到gwmux。处理程序通过endpoint转发请求到grpc端点
err = pb.RegisterSimpleHandlerFromEndpoint(ctx, gwmux, endpoint, dopts)
if err != nil {
log.Fatalf("Register Endpoint err: %v", err)
}
//新建mux,它是http的请求复用器
mux := http.NewServeMux()
//注册gwmux
mux.Handle("/", gwmux)
log.Println(endpoint + " HTTP.Listing whth TLS and token...")
return &http.Server{
Addr: endpoint,
Handler: grpcHandlerFunc(grpcServer, mux),
TLSConfig: getTLSConfig(),
}
}
// grpcHandlerFunc 根据不同的请求重定向到指定的Handler处理
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{})
}
// getTLSConfig获取TLS配置
func getTLSConfig() *tls.Config {
cert, _ := ioutil.ReadFile("../tls/server.pem")
key, _ := ioutil.ReadFile("../tls/server.key")
var demoKeyPair *tls.Certificate
pair, err := tls.X509KeyPair(cert, key)
if err != nil {
grpclog.Fatalf("TLS KeyPair err: %v\n", err)
}
demoKeyPair = &pair
return &tls.Config{
Certificates: []tls.Certificate{*demoKeyPair},
NextProtos: []string{http2.NextProtoTLS}, // HTTP2 TLS支持
}
}
它主要作用是把不用的请求重定向到指定的服务处理,从而实现把HTTP请求转到gRPC服务。
2.gRPC支持HTTP
//使用gateway把grpcServer转成httpServer
httpServer := gateway.ProvideHTTP(Address, grpcServer)
if err = httpServer.Serve(tls.NewListener(listener, httpServer.TLSConfig)); err != nil {
log.Fatal("ListenAndServe: ", err)
}
使用postman测试

在动图中可以看到,我们的gRPC服务已经同时支持RPC和HTTP请求了,而且API接口支持bearer token验证和数据验证。为了方便对接,我们把API接口生成swagger文档。
生成swagger文档
simple.swagger.json
1.安装protoc-gen-swagger
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
2.编译生成simple.swagger.json
到simple.proto文件目录下,编译:
protoc --swagger_out=logtostderr=true:./ ./simple.proto
再次提一下,本人在VSCode中使用VSCode-proto3插件,第一篇有介绍,只要保存,就会自动编译,很方便,无需记忆指令。完整配置如下:
编译生成后把需要的文件留下,不需要的删掉。
把swagger-ui转成Go代码,备用
1.下载swagger-ui
下载地址,把dist目录下的所有文件拷贝我们项目的server/swagger/swagger-ui/目录下。
2.把Swagger UI转换为Go代码
安装go-bindata:
go get -u github.com/jteeuwen/go-bindata/...
回到server/所在目录,运行指令把Swagger UI转成Go代码。
go-bindata --nocompress -pkg swagger -o swagger/datafile.go swagger/swagger-ui/...
这步有坑,必须要回到main函数所在的目录运行指令,因为生成的Go代码中的_bindata 映射了swagger-ui的路径,程序是根据这些路径来找页面的。如果没有在main函数所在的目录运行指令,则生成的路径不对,会报404,无法找到页面。本项目server/端的main函数在server.go中,所以在server/所在目录下运行指令。
var _bindata = map[string]func() (*asset, error){
"swagger/swagger-ui/favicon-16x16.png": swaggerSwaggerUiFavicon16x16Png,
"swagger/swagger-ui/favicon-32x32.png": swaggerSwaggerUiFavicon32x32Png,
"swagger/swagger-ui/index.html": swaggerSwaggerUiIndexHtml,
"swagger/swagger-ui/oauth2-redirect.html": swaggerSwaggerUiOauth2RedirectHtml,
"swagger/swagger-ui/swagger-ui-bundle.js": swaggerSwaggerUiSwaggerUiBundleJs,
"swagger/swagger-ui/swagger-ui-bundle.js.map": swaggerSwaggerUiSwaggerUiBundleJsMap,
"swagger/swagger-ui/swagger-ui-standalone-preset.js": swaggerSwaggerUiSwaggerUiStandalonePresetJs,
"swagger/swagger-ui/swagger-ui-standalone-preset.js.map": swaggerSwaggerUiSwaggerUiStandalonePresetJsMap,
"swagger/swagger-ui/swagger-ui.css": swaggerSwaggerUiSwaggerUiCss,
"swagger/swagger-ui/swagger-ui.css.map": swaggerSwaggerUiSwaggerUiCssMap,
"swagger/swagger-ui/swagger-ui.js": swaggerSwaggerUiSwaggerUiJs,
"swagger/swagger-ui/swagger-ui.js.map": swaggerSwaggerUiSwaggerUiJsMap,
}
对外提供swagger-ui
1.在swagger/目录下新建swagger.go文件
package swagger
import (
"log"
"net/http"
"path"
"strings"
assetfs "github.com/elazarl/go-bindata-assetfs"
)
//ServeSwaggerFile 把proto文件夹中的swagger.json文件暴露出去
func ServeSwaggerFile(w http.ResponseWriter, r *http.Request) {
if !strings.HasSuffix(r.URL.Path, "swagger.json") {
log.Printf("Not Found: %s", r.URL.Path)
http.NotFound(w, r)
return
}
p := strings.TrimPrefix(r.URL.Path, "/swagger/")
// "../proto/"为.swagger.json所在目录
p = path.Join("../proto/", p)
log.Printf("Serving swagger-file: %s", p)
http.ServeFile(w, r, p)
}
//ServeSwaggerUI 对外提供swagger-ui
func ServeSwaggerUI(mux *http.ServeMux) {
fileServer := http.FileServer(&assetfs.AssetFS{
Asset: Asset,
AssetDir: AssetDir,
Prefix: "swagger/swagger-ui", //swagger-ui文件夹所在目录
})
prefix := "/swagger-ui/"
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
}
2.注册swagger
在gateway.go中添加如下代码
//注册swagger
mux.HandleFunc("/swagger/", swagger.ServeSwaggerFile)
swagger.ServeSwaggerUI(mux)
到这里我们已经完成了swagger文档的添加工作了,由于谷歌浏览器不能使用自己制作的TLS证书,所以我们用火狐浏览器进行测试。
用火狐浏览器打开:https://127.0.0.1:8000/swagger-ui/
在最上面地址栏输入:https://127.0.0.1:8000/swagger/simple.swagger.json
然后就可以看到swagger生成的API文档了。

还有个问题,我们使用了bearer token进行接口验证的,怎么把bearer token也添加到swagger中呢?
最后我在grpc-gatewayGitHub上的这个Issues找到解决办法。
在swagger中配置bearer token
1.修改simple.proto文件
syntax = "proto3";
package proto;
import "github.com/mwitkow/go-proto-validators/validator.proto";
import "go-grpc-example/10-grpc-gateway/proto/google/api/annotations.proto";
import "go-grpc-example/10-grpc-gateway/proto/google/options/annotations.proto";
message InnerMessage {
// some_integer can only be in range (1, 100).
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
// some_float can only be in range (0;1).
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
}
message OuterMessage {
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
}
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
security_definitions: {
security: {
key: "bearer"
value: {
type: TYPE_API_KEY
in: IN_HEADER
name: "Authorization"
description: "Authentication token, prefixed by Bearer: Bearer "
}
}
}
security: {
security_requirement: {
key: "bearer"
}
}
info: {
title: "grpc gateway sample";
version: "1.0";
license: {
name: "MIT";
};
}
schemes: HTTPS
};
service Simple{
rpc Route (InnerMessage) returns (OuterMessage){
option (google.api.http) ={
post:"/v1/example/route"
body:"*"
};
// //禁用bearer token
// option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
// security: { } // Disable security key
// };
}
}
2.重新编译生成simple.swagger.json
大功告成!
验证测试
1.添加bearer token

2.调用接口,正确返回数据

3.传递不合规则的数据,返回违反数据验证逻辑错误

总结
本篇介绍了如何使用grpc-gateway让gRPC同时支持HTTP,最终转成的Restful Api支持bearer token验证、数据验证。同时生成swagger文档,方便API接口对接。
教程源码地址:https://github.com/Bingjian-Zhu/go-grpc-example
参考文档
https://www.jb51.net/article/251828.htm
https://www.jb51.net/article/251837.htm
今天关于《Go gRPC进阶教程gRPC转换HTTP》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
GoGrpcGateway兼容HTTP协议文档自动生成网关
- 上一篇
- GoGrpcGateway兼容HTTP协议文档自动生成网关
- 下一篇
- Go gRPC服务proto数据验证进阶教程
-
- 舒心的小兔子
- 太全面了,码起来,感谢老哥的这篇文章内容,我会继续支持!
- 2023-01-25 14:32:00
-
- 热情的萝莉
- 细节满满,已收藏,感谢大佬的这篇技术文章,我会继续支持!
- 2023-01-18 12:29:39
-
- 虚心的钢笔
- 感谢大佬分享,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢老哥分享技术贴!
- 2023-01-16 15:02:16
-
- 羞涩的滑板
- 这篇文章内容太及时了,太详细了,感谢大佬分享,mark,关注作者了!希望作者能多写Golang相关的文章。
- 2023-01-11 16:09:34
-
- 香蕉月饼
- 这篇文章真及时,太细致了,很有用,码住,关注楼主了!希望楼主能多写Golang相关的文章。
- 2023-01-08 21:15:34
-
- 老实的吐司
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢楼主分享技术文章!
- 2023-01-07 09:39:22
-
- 漂亮的彩虹
- 这篇文章内容太及时了,作者大大加油!
- 2023-01-07 05:31:18
-
- 精明的凉面
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢up主分享技术文章!
- 2023-01-06 15:33:14
-
- 含蓄的可乐
- 很详细,mark,感谢up主的这篇技术贴,我会继续支持!
- 2023-01-05 15:26:02
-
- 义气的爆米花
- 这篇技术贴太及时了,太细致了,很有用,收藏了,关注老哥了!希望老哥能多写Golang相关的文章。
- 2022-12-31 19:40:41
-
- Golang · Go教程 | 1天前 | map · 并发安全 · RWMutex · sync.Map · Go教程 · 并发安全 RWMutex sync.Map Go map并发读写 go test race
- Go map 并发读写崩溃怎么办:从复现报错到 RWMutex 修复的完整流程
- 272浏览 收藏
-
- Golang · Go教程 | 3天前 | singleflight · 并发控制 · Go教程 · 缓存治理 · 接口优化 · Go 并发请求 缓存击穿 singleflight 缓存回填
- Go singleflight 防缓存击穿实战:相同请求只查一次数据库
- 114浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ljg-skills
- ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
- 153次使用
-
- MELO音乐
- MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
- 171次使用
-
- UniScribe
- UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
- 149次使用
-
- 剧云
- 剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
- 305次使用
-
- 万象有声
- 万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
- 308次使用
-
- 基于微服务框架go-micro开发gRPC应用程序
- 2023-01-01 282浏览
-
- Golang gRPC HTTP协议转换示例
- 2022-12-24 213浏览
-
- GoGrpcGateway兼容HTTP协议文档自动生成网关
- 2022-12-28 135浏览
-
- Go gRPC服务proto数据验证进阶教程
- 2023-01-09 360浏览
-
- Go gRPC服务进阶middleware使用教程
- 2022-12-29 212浏览

