前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >GRPC怎么用

GRPC怎么用

作者头像
用户2825413
发布于 2022-04-19 01:39:31
发布于 2022-04-19 01:39:31
5K00
代码可运行
举报
运行总次数:0
代码可运行

本文主题

本文大部分都是代码案例, 如果您对 grpc 感兴趣, 可以作为基础参考的一部分.

  1. 介绍了 proto 生成 pb 文件常用命令
  2. 如何构造 grpc 服务, header头传递、拦截器一些基本操作.
  3. 如何使用 protoc-gen-grpc-gateway 插件生成同时支持 grpc 和 http 访问请求.

声明 proto

定义proto文件, 返回Msg

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
syntax = "proto3";

package server;

option go_package = ".;testServer";

service testServer {
  rpc SayHello (Request) returns(Response){
  
  }
}

message Request {

}

message Response {
  string Msg = 1;
}

生成pb message结构文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protoc -I pb/ --go_out=./pb server.proto

生成grpc服务文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protoc  -I pb/ --go-grpc_out=./pb server.proto

-I 表示指定proto的目录 *_out 表示指定输出的目录 *.proto表示源proto的文件名

执行完成后, 我们将会看到 server.pb.go 和 server_grpc.pb.go 两个文件

grpc 服务实现

grpc server服务实现

业务逻辑部分(pb rpc中定义的接口实现)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Server struct {
 testServer.UnimplementedTestServerServer
}

func (s *Server) SayHello(ctx context.Context, t *testServer.Request) (*testServer.Response, error) {
 //获取传递的metadata
  md, _ := metadata.FromIncomingContext(ctx)

 log.Println("xxxx", md)
 return &testServer.Response{Msg: "Hello world"}, nil
}

UnimplementedTestServerServer 的作用是将源pb文件 rpc 方法全部生成为默认实现, 这么做的目的在我们在变更 rpc 接口时, 不会因为未全部实现 导致 register 失败而无法运行, 而是将会执行 UnimplementedTestServerServer 的方法, 例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (UnimplementedTestServerServer) SayHello(context.Context, *Request) (*Response, error) {
 return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
}

metadata.FromIncomingContext 是获取 grpc 请求的头部参数,

http1.* 传递参数通过header头, 而对应的 http2 传递 header 参数主要依赖metadata, grpc底层依赖 http2, 所以也是依赖 metadata 获取 header 头参数的.

metadata 在实现上是比较简单的, 底层就是一个 map 的结构.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type MD map[string][]string

func FromIncomingContext(ctx context.Context) (MD, bool) {
 md, ok := ctx.Value(mdIncomingKey{}).(MD)
 if !ok {
  return nil, false
 }
 out := MD{}
 for k, v := range md {
  // We need to manually convert all keys to lower case, because MD is a
  // map, and there's no guarantee that the MD attached to the context is
  // created using our helper functions.
  key := strings.ToLower(k)
  out[key] = v
 }
 return out, true
}
grpc server 服务

grpc.UnaryServerInterceptor 是我们的拦截器, 通过实现 unaryServerInterceptor 方法, 我们将会在入口拦截请求参数进行处理, 比如验证鉴权操作

Server对象就是我们上面 rpc 接口的实现, 我们通过 RegisterTestServerServer 注册到 srv上

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//拦截器
ints := []grpc.UnaryServerInterceptor{
  unaryServerInterceptor(),
}
grpcOpts := []grpc.ServerOption{
  grpc.ChainUnaryInterceptor(ints...),
}

//new grpc server
srv := grpc.NewServer(grpcOpts...)

//grpc server 注册server服务
server := &Server{}
testServer.RegisterTestServerServer(srv, server)

//grpc server绑定端口
listener, err := net.Listen("tcp", ":12345")
if err != nil {
  log.Fatalf("failed to listen: %v", err)
}

err = srv.Serve(listener)
if err != nil {
  log.Fatalf("failed to serve: %v", err)
}

unaryServerInterceptor 拦截器实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func unaryServerInterceptor() grpc.UnaryServerInterceptor {
 return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
  //获取md参数并打印
  md, _ := metadata.FromIncomingContext(ctx)
  log.Println(md)

  replyHeader := metadata.MD{}

  //todo

  h := func(ctx context.Context, req interface{}) (interface{}, error) {
   return handler(ctx, req)
  }

  reply, err := h(ctx, req)

    //设置响应头
  if len(replyHeader) > 0 {
   _ = grpc.SetHeader(ctx, replyHeader)
  }
  return reply, err
 }
}

grpc client 调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

conn, err := grpc.Dial(":12345", grpc.WithInsecure())
if err != nil {
 panic(err)
}

client := testServer.NewTestServerClient(conn)

ctx := context.Background()
md := metadata.New(map[string]string{"key1": "小文文", "key2": "小方方"})
ctx = metadata.NewOutgoingContext(ctx, md)

response, err := client.SayHello(ctx, &testServer.Request{})
log.Println(response, err, ctx)

HTTP1.* 和 GRPC 共同提供服务

如何使用一套proto协议可以同时支持 http1.* 和 grpc 调用呢?

这里我们使用一个proto的插件 protoc-gen-grpc-gateway, 来实现这个功能.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//安装插件
go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway

http需要指定访问路径, 我们需要稍微改造下上面的 proto 协议

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//...
import "google/api/annotations.proto";
//...

service testServer {
  rpc SayHello (Request) returns(Response){
    option (google.api.http) = {
      get: "/hello",
    };
  }
}

message Request {

}

message Response {
  string Msg = 1;
}

这里我们使用option命令声明了一个 get 请求 /hello

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protoc -I pb/ --proto_path=./ --go_out=./pb --go-grpc_out=./pb --grpc-gateway_out=./pb server.proto

我们新增加了一个插件 --grpc-gateway_out , 生成 pb.gw.go文件, 提供 RegisterTestServerHandler 方法进行路由注册.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//register server (http->SayHello)
func RegisterTestServerHandlerServer(ctx context.Context, mux *runtime.ServeMux, server TestServerServer) error {

 mux.Handle("GET", pattern_TestServer_SayHello_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
  //...
    
    //调用的本地
    resp, md, err := local_request_TestServer_SayHello_0(rctx, inboundMarshaler, server, req, pathParams)
   
    //...
 })

 return nil
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//register client (http -> grpc -> SayHello)
func RegisterTestServerHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TestServerClient) error {

 mux.Handle("GET", pattern_TestServer_SayHello_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
  
  //...
    //调用的grpc服务
  resp, md, err := request_TestServer_SayHello_0(rctx, inboundMarshaler, client, req, pathParams)
  
  //...
 })

 return nil
}

这里可以看到两种 register 是不一样的, 一种是本地直接调用 pb rpc 声明的方法, 另一种是 http 再调用 grpc 服务, 下面我们看下示例

RegisterTestServerHandlerServer 注册示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gwmux := runtime.NewServeMux(
 runtime.WithIncomingHeaderMatcher(func(key string) (string, bool) { //自定义header头过滤规则
  //todo 此处需要返回header key, 才能在 md 中获取到header头信息
  return key, true
 }),
)

err = testServer.RegisterTestServerHandlerServer(context.Background(), gwmux, server)
if err != nil {
 log.Fatalln("Failed to register gateway:", err)
}

gwServer := &http.Server{
 Addr:    ":8888",
 Handler: gwmux,
}
log.Fatalln(gwServer.ListenAndServe())

RegisterTestServerHandlerClient注册示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//首先链接grpc服务地址
conn, err := grpc.Dial(
 ":12345",
  grpc.WithInsecure(),
)
if err != nil {
 log.Fatalln("Failed to dial server:", err)
}
client := testServer.NewTestServerClient(conn)

gwmux := runtime.NewServeMux(
 runtime.WithIncomingHeaderMatcher(func(key string) (string, bool) { //自定义header头过滤规则
  //todo 此处需要返回header key, 才能在 md 中获取到header头信息
  return key, true
 }),
)

err = testServer.RegisterTestServerHandlerClient(context.Background(), gwmux, client)
if err != nil {
 log.Fatalln("Failed to register gateway:", err)
}

gwServer := &http.Server{
 Addr:    ":8888",
 Handler: gwmux,
}
log.Fatalln(gwServer.ListenAndServe())

参考

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

https://www.lixueduan.com/post/grpc/07-grpc-gateway/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小宇技术研究所 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
架构如何为业务和技术“服务”(1)
前言 为提升架构对于项目,产品的贡献度,更好的服务于业务和技术,本文将探讨架构的现状和规划未来架构的目标。 在讨论架构、业务、技术的问题前,请耐心的阅读完本文有关架构、企业架构、软件架构、架构师的概念性定义,很多时候我们阅读文章都是“秒杀”风格的,只看自己感兴趣的部分,不看长篇大论,只有明确了这些概念定义,才能明白我们现在讨论的主旨。 1,架构定义 1.1,架构 架构是针对某种特定目标系统的具有体系性的、普遍性的问题而提供的通用的解决方案,架构往往是对复杂形态的一种共性的体系抽象。 一个架构是系统的基本
用户1177503
2018/02/26
1.4K0
架构概念简析及初识架构师
在软件设计中,人们对很多概念存在误解,或者模糊不清,其中一个最为普遍的误解就是:将架构和框架混为一谈。还有对类库和框架的区别是什么很疑惑。本文就这些概念性的问题做一个总结性区分以方便大家理解其中的内涵,也算是架构设计的一篇入门级文章。
進无尽
2018/09/12
5150
架构概念简析及初识架构师
要想做好架构可视化,你必须弄懂这十个关系
在企业数字化转型过程中,做好企业级架构的治理至关重要。而架构的可视化是其中关键的一环。围绕可视化的架构,干系人能够更好地理解和沟通企业中不同组织、系统和技术组件的结构和关系。以便不断对企业的系统架构进行优化。 在 ArcSummit 全球架构师峰会(上海站)2023 上,InfoQ 邀请了 Thoughtworks 首席咨询师钟敬,他以《企业级架构可视化实践》为主题展开了分享,本文为分享整理~期待对您在企业中开展架构治理工作有所启发。
深度学习与Python
2023/08/09
6170
要想做好架构可视化,你必须弄懂这十个关系
干货:软件架构发展历程
计算机科学和程序设计的飞速发展,使得软件设计应用到从航空航天到日常生活的方方面面。单个人开发一段小程序的做法早就过时,大范围协作的工程化时代随即到来。
技术zhai
2019/02/15
4K1
架构师是怎样炼成的
软件架构师定义 软件工程师的职业发展方向: 软件架构师: 制定高级设计决策,并确定技术标准,包括编程标准,工具和平台的软件专家 软件架构: 系统的基本组织构成,这种组织主要体现在其组件,组
攻城狮Chova
2022/01/22
6730
架构师是怎样炼成的
微课堂 | 云计算平台项目团队组织架构与缘起(PPT)
本文为普元软件产品部副总兼SOA产品线总经理刘相在普元云计算架构设计群的微课堂分享,转载需保留此处版权申明。 大家好!本次微课堂为大家介绍普元云计算团队从数字化企业云计算平台理念提出,到种子团队、研发
yuanyi928
2018/03/30
3.1K0
微课堂 | 云计算平台项目团队组织架构与缘起(PPT)
架构师之路一-架构师入门指引
导读:本系列文章教你怎么样成为一名架构师,而本篇文章则带你先认识一下什么是架构师,架构师的工作是什么?
JAVA日知录
2020/03/12
3.3K0
中台之上(二):为什么业务架构存在 20 多年,技术人员还觉得它有点虚?
业务架构这个词大家时常听到,但是能解释得清楚的却不多,撩撩度娘,你就会发现,不少人问及业务架构和应用架构的关系,聊天时,也常有人问起业务架构师和产品经理什么区别?业务架构分析和需求分析什么区别?为了思考这个问题,我把《软件工程》、《软件系统架构》、《系统分析与设计》都翻了,这些经典教材确实没讲过业务架构这件事;我把《聊聊架构》也翻了,发现其中的讨论有解释到业务、架构和技术的关系,但是也没有特别强调业务架构,所以本文就先梳理下几个较为有名的业务架构理论。
xcbeyond
2021/03/16
6510
中台之上(二):为什么业务架构存在 20 多年,技术人员还觉得它有点虚?
汽车软件架构学习笔记(一):九问软件架构
架构一般指的是软件系统宏观层面的设计部分,前面讲到架构是骨架,关注于整体,一般不会关注于细节。
Frank909
2022/01/11
9320
汽车软件架构学习笔记(一):九问软件架构
白话架构设计为你阐述什么是架构设计,架构设计的三大原则是什么
前面两篇文章给大家介绍了我们实战的CMS系统的数据库设计,源码也已经上传到服务器上了。今天我们就好聊聊架构设计,在开始之前先给大家分享一下这几天我一直在听的《从零开始学架构》里面关于架构设计的定义以及架构设计的三大原则,希望能对大家有所启发。有着这些基础之后,我们再基于此搭建我们的项目框架吧!如果你在阅读的过程中有任何的问题,欢迎大家在留言区进行留言
依乐祝
2018/12/14
2.3K0
架构名词分析 | 系统与子系统,模块与组件,框架与架构,这些概念的含义和关系是怎样的?
技术朋友应该看过公司架构师画的各种架构图,五花八门,各种框框,还涉及很多概念,比如系统,子系统,模块,组件,框架等等。他们都有出现在架构师的架构图里,那这些名词都是什么含义呢?它们之间又存在什么样的关系呢?架构的本质又是什么呢?
蜗牛互联网
2021/07/21
7.3K0
数字化转型中,如何高效设计业务架构?
数字化转型的传统过程中,企业往往不关注架构设计,或者只关注 IT 层面,未从企业架构宏观视角出发进行设计,特别是在整个企业架构中扮演着至关重要的业务架构。 业务架构是明确从企业战略计划到企业各部分如何运转的工具,其从企业的全局视角,对后续IT架构及业务运营方向提供指导。 本文我们主要介绍什么是业务架构?业务架构包括哪些主要内容?以及如何有效构建业务架构? 1 什么是业务架构 业务架构(Business Architecture)来自业务,业务最终的目的是“售出产品,换取利润”,业务是为企业产生盈利的工作和经
博文视点Broadview
2023/04/19
1.3K0
数字化转型中,如何高效设计业务架构?
脱离业务的技术架构,都只是一团废纸,教你从0-1建设业务架构
无论你是什么首席架构师也好,技术负责人也好,你必须要承认,所有的技术和架构都是为业务服务的,脱离了业务,架构就是一团废纸。
IT大咖说
2020/04/21
1.1K1
脱离业务的技术架构,都只是一团废纸,教你从0-1建设业务架构
模块架构不是软件成功的“决定因素”
【本文是09年的一篇旧文,出于某些原因,对原文内容有删减,在这里整理后重新发表】 前言 感谢XXX对我们技术,对我们公司产品提出这些意见,我们公司卖的是软件产品,开发软件是一件技术活,说实话,要把技术上面的东西用非技术的语言来向大家交流,的确不是容易的事情。 架构的概念和架构的变迁 首先,“架构”一词我们技术和大家有不同的理解,从于冬琪提出的“平行架构”和“树形架构”的字面意思来理解,他(暂且用这个“他”而不是“她”,现在我们只见其声不见其人,不知者无罪,假设错了还请见谅:) )的关注点应该是“功能模
用户1177503
2018/02/26
6340
鹅厂架构师谈:如何做好架构设计?
# 关注并星标腾讯云开发者 # 每周3 | 谈谈我在腾讯的架构设计经验 # 第1期 | 黄规速:鹅厂架构师谈:如何做好架构设计?
腾讯云开发者
2023/08/03
1K0
鹅厂架构师谈:如何做好架构设计?
Android开发架构思考及经验总结(上)
架构设计,到底是什么呢?基于这段时间的学习和自己的一些思考,我认为架构是基于产品和技术所达成的一种共识。我不是专业的架构师,也不是经验老道的开发者。本文目的有三,一是整理这段时间的架构学习和思考以及总结这一年的开发经验教训,二是希望能够与各位朋友探讨移动端App的架构设计,三是希望我们每一个应用开发者能够拥有架构的意识。个人的水平有限,诸多不对的地方,恳请批评指正。
open
2020/03/19
1.6K0
Android开发架构思考及经验总结(上)
金融企业架构数字化实践
国资委在《关于加快推进国有企业数字化转型工作的通知》中明确指出,以企业架构为核心构建现代化IT治理体系,促进IT投资与业务变革发展持续适配。在信创迁移和数字化转型的双重推进下,企业架构有效承接战略、对齐业务和科技,使得企业各领域形成一个有机整体,更快速地助力企业应对挑战、响应变化,并增强自身的竞争力。
yuanyi928
2022/09/26
6890
金融企业架构数字化实践
系统架构师论文-论软件产品线技术(测井工程服务)
根据公司软件系统开发的需要,我们在软件的开发过程中引入了软件产品线技术,成立了基于软件产品线的项目组。本人有幸参加了该项目,并在其中担任软件分析与设计、软件产品线核心资源开发的工作。 在软件产品线的开发过程中,我们使用了 ROSE建模工具,有效地完成了产品线中核心资源和产品的建模分析与设计实现;我们使用了国际标准POSC数据模型框架,有效地解决了数据的多样性与可扩展性,实现了统一开放的测井数据访问系统;建立了统一的可扩展的地质绘制组件和统一公用的数据处理模块。最终圆满的完成了公司产品线的建立和各子系统的开发。
cwl_java
2019/10/26
4120
【极客世界】架构到底是指什么?
对于技术人员来说,“架构”是一个再常见不过的词了。我们会对新员工培训整个系统的架构,参加架构设计评审,学习业界开源系统(例如,MySQL、Hadoop)的架构,研究大公司的架构实现(例如,微信架构、淘宝架构)……虽然
用户3894598
2019/12/12
7890
【极客世界】架构到底是指什么?
【超详解PPT】元数据驱动的微服务架构(下)
上次分享了两个部分:微服务架构需要元数据,微服务与元数据的关系,那么微服务中的元数据中具体如何应用,有哪些应用场景?我们接下来看一下——微服务中元数据的价值,了解元数据在微服务中具体的应用价值点。
yuanyi928
2018/03/30
2.3K0
【超详解PPT】元数据驱动的微服务架构(下)
推荐阅读
相关推荐
架构如何为业务和技术“服务”(1)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档