惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
博客园_首页
T
Tailwind CSS Blog
aimingoo的专栏
aimingoo的专栏
A
About on SuperTechFans
T
The Blog of Author Tim Ferriss
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
P
Proofpoint News Feed
博客园 - 司徒正美
有赞技术团队
有赞技术团队
Engineering at Meta
Engineering at Meta
Last Week in AI
Last Week in AI
MongoDB | Blog
MongoDB | Blog

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
gRPC-gateway 源码阅读与分析
Jiajun Huang · 2018-08-08 · via Jiajun的技术笔记

https://github.com/grpc-ecosystem/grpc-gateway

首先看一下要怎么用这个库,README里写着:

protoc -I/usr/local/include -I. \
    -I$GOPATH/src \
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
    --grpc-gateway_out=logtostderr=true:. \
    path/to/your_service.proto

搜索 protoc plugin 可以得到:https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.compiler.plugin

可以得到这几个结论:

  • protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR 其中NAME是插件的名字,=后边接的是二进制的路径
  • plugin 接受一个 CodeGeneratorRequest,返回一个 CodeGeneratorResponse

https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/plugin.proto

从README中可以看到我们是这样安装 grpc-gateway 的: go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway

然后我们就到 protoc-gen-grpc-gateway 中看 main.go:

func main() {
	flag.Parse()
	defer glog.Flush()

	reg := descriptor.NewRegistry()

	glog.V(1).Info("Parsing code generator request")
	req, err := codegenerator.ParseRequest(os.Stdin)
	if err != nil {
		glog.Fatal(err)
	}
	glog.V(1).Info("Parsed code generator request")
	if req.Parameter != nil {
		for _, p := range strings.Split(req.GetParameter(), ",") {
			spec := strings.SplitN(p, "=", 2)
			if len(spec) == 1 {
				if err := flag.CommandLine.Set(spec[0], ""); err != nil {
					glog.Fatalf("Cannot set flag %s", p)
				}
				continue
			}
			name, value := spec[0], spec[1]
			if strings.HasPrefix(name, "M") {
				reg.AddPkgMap(name[1:], value)
				continue
			}
			if err := flag.CommandLine.Set(name, value); err != nil {
				glog.Fatalf("Cannot set flag %s", p)
			}
		}
	}

	g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType)

	if *grpcAPIConfiguration != "" {
		if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil {
			emitError(err)
			return
		}
	}

	reg.SetPrefix(*importPrefix)
	reg.SetImportPath(*importPath)
	reg.SetAllowDeleteBody(*allowDeleteBody)
	if err := reg.Load(req); err != nil {
		emitError(err)
		return
	}

	var targets []*descriptor.File
	for _, target := range req.FileToGenerate {
		f, err := reg.LookupFile(target)
		if err != nil {
			glog.Fatal(err)
		}
		targets = append(targets, f)
	}

	out, err := g.Generate(targets)
	glog.V(1).Info("Processed code generator request")
	if err != nil {
		emitError(err)
		return
	}
	emitFiles(out)
}

其中:

  • req, err := codegenerator.ParseRequest(os.Stdin) 跳进去看,是从标准输入读取参数,然后返回一个 *plugin.CodeGeneratorRequest 对象。就是上面的proto文件中的CodeGeneratorRequest
  • g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType) 生成一个 gen.Generator 对象
  • out, err := g.Generate(targets) 生成代码
  • 跟进去,func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGeneratorResponse_File, error) 函数的实现, 发现调用了 code, err := g.generate(file)
  • 调用了 func (g *generator) generate(file *descriptor.File) (string, error), 调用了 protoc-gen-grpc-gateway/gengateway/template.go 中的代码
  • template.go 下面就是我们要生成的代码的模板

如果生成一个demo看看,就知道,模板做的事情就是每接受一个HTTP请求,就生成一个gRPC请求。