广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Go gRPC服务进阶middleware使用教程
  • 150
分享到

Go gRPC服务进阶middleware使用教程

2024-04-02 19:04:59 150人浏览 薄情痞子
摘要

目录前言Go-grpc-middleware简介grpc_zap日志记录grpc_auth认证grpc_recovery恢复总结前言 之前介绍了gRPC中TLS认证和自定义方法认证,

前言

之前介绍了gRPC中TLS认证和自定义方法认证,最后还简单介绍了gRPC拦截器的使用。gRPC自身只能设置一个拦截器,所有逻辑都写一起会比较乱。本篇简单介绍go-grpc-middleware的使用,包括grpc_zap、grpc_auth和grpc_recovery。

go-grpc-middleware简介

go-grpc-middleware封装了认证(auth), 日志( logging), 消息(message), 验证(validation), 重试(retries) 和监控(retries)等拦截器。

安装

 go get GitHub.com/grpc-ecosystem/go-grpc-middleware

使用

import "github.com/grpc-ecosystem/go-grpc-middleware"
myServer := grpc.NewServer(
    grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
        grpc_ctxtags.StreamServerInterceptor(),
        grpc_opentracing.StreamServerInterceptor(),
        grpc_prometheus.StreamServerInterceptor,
        grpc_zap.StreamServerInterceptor(zapLogger),
        grpc_auth.StreamServerInterceptor(myAuthFunction),
        grpc_recovery.StreamServerInterceptor(),
    )),
    grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
        grpc_ctxtags.UnaryServerInterceptor(),
        grpc_opentracing.UnaryServerInterceptor(),
        grpc_prometheus.UnaryServerInterceptor,
        grpc_zap.UnaryServerInterceptor(zapLogger),
        grpc_auth.UnaryServerInterceptor(myAuthFunction),
        grpc_recovery.UnaryServerInterceptor(),
    )),
)

grpc.StreamInterceptor中添加流式RPC的拦截器。

grpc.UnaryInterceptor中添加简单RPC的拦截器。

grpc_zap日志记录

1.创建zap.Logger实例

func Zapinterceptor() *zap.Logger {
	logger, err := zap.NewDevelopment()
	if err != nil {
		log.Fatalf("failed to initialize zap logger: %v", err)
	}
	grpc_zap.ReplaceGrpcLogger(logger)
	return logger
}

2.把zap拦截器添加到服务端

grpcServer := grpc.NewServer(
	grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
			grpc_zap.StreamServerInterceptor(zap.ZapInterceptor()),
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
			grpc_zap.UnaryServerInterceptor(zap.ZapInterceptor()),
		)),
	)

3.日志分析

各个字段代表的意思如下:

{
	  "level": "info",						// string  zap log levels
	  "msg": "finished unary call",					// string  log message
	  "grpc.code": "OK",						// string  grpc status code
	  "grpc.method": "Ping",					/ string  method name
	  "grpc.service": "mwitkow.testproto.TestService",              // string  full name of the called service
	  "grpc.start_time": "2006-01-02T15:04:05Z07:00",               // string  RFC3339 representation of the start time
	  "grpc.request.deadline": "2006-01-02T15:04:05Z07:00",         // string  RFC3339 deadline of the current request if supplied
	  "grpc.request.value": "something",				// string  value on the request
	  "grpc.time_ms": 1.345,					// float32 run time of the call in ms
	  "peer.address": {
	    "IP": "127.0.0.1",						// string  IP address of calling party
	    "Port": 60216,						// int     port call is coming in on
	    "Zone": ""							// string  peer zone for caller
	  },
	  "span.kind": "server",					// string  client | server
	  "system": "grpc",						// string
	  "custom_field": "custom_value",				// string  user defined field
	  "custom_tags.int": 1337,					// int     user defined tag on the ctx
	  "custom_tags.string": "something"				// string  user defined tag on the ctx
}

4.把日志写到文件中

上面日志是在控制台输出的,现在我们把日志写到文件中,修改ZapInterceptor方法。

import (
	grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)
// ZapInterceptor 返回zap.logger实例(把日志写到文件中)
func ZapInterceptor() *zap.Logger {
	w := zapcore.AddSync(&lumberjack.Logger{
		Filename:  "log/debug.log",
		MaxSize:   1024, //MB
		LocalTime: true,
	})
	config := zap.NewProductionEncoderConfig()
	config.EncodeTime = zapcore.ISO8601TimeEncoder
	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(config),
		w,
		zap.NewAtomicLevel(),
	)
	logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
	grpc_zap.ReplaceGrpcLogger(logger)
	return logger
}

grpc_auth认证

go-grpc-middleware中的grpc_auth默认使用authorization认证方式,以authorization为头部,包括basic, bearer形式等。下面介绍bearer token认证。bearer允许使用access key(如jsON WEB Token (Jwt))进行访问。

1.新建grpc_auth服务端拦截器

// TokenInfo 用户信息
type TokenInfo struct {
	ID    string
	Roles []string
}
// AuthInterceptor 认证拦截器,对以authorization为头部,形式为`bearer token`的Token进行验证
func AuthInterceptor(ctx context.Context) (context.Context, error) {
	token, err := grpc_auth.AuthFromMD(ctx, "bearer")
	if err != nil {
		return nil, err
	}
	tokenInfo, err := parseToken(token)
	if err != nil {
		return nil, grpc.Errorf(codes.Unauthenticated, " %v", err)
	}
	//使用context.WithValue添加了值后,可以用Value(key)方法获取值
	newCtx := context.WithValue(ctx, tokenInfo.ID, tokenInfo)
	//log.Println(newCtx.Value(tokenInfo.ID))
	return newCtx, nil
}
//解析token,并进行验证
func parseToken(token string) (TokenInfo, error) {
	var tokenInfo TokenInfo
	if token == "grpc.auth.token" {
		tokenInfo.ID = "1"
		tokenInfo.Roles = []string{"admin"}
		return tokenInfo, nil
	}
	return tokenInfo, errors.New("Token无效: bearer " + token)
}
//从token中获取用户唯一标识
func userClaimFromToken(tokenInfo TokenInfo) string {
	return tokenInfo.ID
}

代码中的对token进行简单验证并返回模拟数据。

2.客户端请求添加bearer token

实现和上篇的自定义认证方法大同小异。gRPC 中默认定义了 PerRPCCredentials,是提供用于自定义认证的接口,它的作用是将所需的安全认证信息添加到每个RPC方法的上下文中。其包含 2 个方法:

GetRequestMetadata:获取当前请求认证所需的元数据

RequireTransportSecurity:是否需要基于 TLS 认证进行安全传输

接下来我们实现这两个方法

// Token token认证
type Token struct {
	Value string
}
const headerAuthorize string = "authorization"
// GetRequestMetadata 获取当前请求认证所需的元数据
func (t *Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{headerAuthorize: t.Value}, nil
}
// RequireTransportSecurity 是否需要基于 TLS 认证进行安全传输
func (t *Token) RequireTransportSecurity() bool {
	return true
}

注意:这里要以authorization为头部,和服务端对应。

发送请求时添加token

//从输入的证书文件中为客户端构造TLS凭证
	creds, err := credentials.NewClientTLSFromFile("../tls/server.pem", "go-grpc-example")
	if err != nil {
		log.Fatalf("Failed to create TLS credentials %v", err)
	}
	//构建Token
	token := auth.Token{
		Value: "bearer grpc.auth.token",
	}
	// 连接服务器
	conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(&token))

注意:Token中的Value的形式要以bearer token值形式。因为我们服务端使用了bearer token验证方式。

3.把grpc_auth拦截器添加到服务端

grpcServer := grpc.NewServer(cred.TLSInterceptor(),
	grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
	        grpc_auth.StreamServerInterceptor(auth.AuthInterceptor),
			grpc_zap.StreamServerInterceptor(zap.ZapInterceptor()),
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
		    grpc_auth.UnaryServerInterceptor(auth.AuthInterceptor),
			grpc_zap.UnaryServerInterceptor(zap.ZapInterceptor()),
		)),
	)

写到这里,服务端都会拦截请求并进行bearer token验证,使用bearer token是规范了与Http请求的对接,毕竟gRPC也可以同时支持HTTP请求。

grpc_recovery恢复

把gRPC中的panic转成error,从而恢复程序。

1.直接把grpc_recovery拦截器添加到服务端

最简单使用方式

grpcServer := grpc.NewServer(cred.TLSInterceptor(),
	grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
	        grpc_auth.StreamServerInterceptor(auth.AuthInterceptor),
			grpc_zap.StreamServerInterceptor(zap.ZapInterceptor()),
			grpc_recovery.StreamServerInterceptor,
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
		    grpc_auth.UnaryServerInterceptor(auth.AuthInterceptor),
			grpc_zap.UnaryServerInterceptor(zap.ZapInterceptor()),
            grpc_recovery.UnaryServerInterceptor(),
		)),
	)

2.自定义错误返回

当panic时候,自定义错误码并返回。

// RecoveryInterceptor panic时返回Unknown错误吗
func RecoveryInterceptor() grpc_recovery.Option {
	return grpc_recovery.WithRecoveryHandler(func(p interface{}) (err error) {
		return grpc.Errorf(codes.Unknown, "panic triggered: %v", p)
	})
}

添加grpc_recovery拦截器到服务端

grpcServer := grpc.NewServer(cred.TLSInterceptor(),
	grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
	        grpc_auth.StreamServerInterceptor(auth.AuthInterceptor),
			grpc_zap.StreamServerInterceptor(zap.ZapInterceptor()),
			grpc_recovery.StreamServerInterceptor(recovery.RecoveryInterceptor()),
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
		    grpc_auth.UnaryServerInterceptor(auth.AuthInterceptor),
			grpc_zap.UnaryServerInterceptor(zap.ZapInterceptor()),
            grpc_recovery.UnaryServerInterceptor(recovery.RecoveryInterceptor()),
		)),
	)

总结

本篇介绍了go-grpc-middleware中的grpc_zap、grpc_auth和grpc_recovery拦截器的使用。go-grpc-middleware中其他拦截器可参考GitHub学习使用。

教程源码地址:https://github.com/Bingjian-Zhu/go-grpc-example

以上就是Go gRPC服务进阶middleware使用教程的详细内容,更多关于Go gRPC服务middleware的资料请关注编程网其它相关文章!

您可能感兴趣的文档:

--结束END--

本文标题: Go gRPC服务进阶middleware使用教程

本文链接: https://www.lsjlt.com/news/151649.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go gRPC服务进阶middleware使用教程
    目录前言go-grpc-middleware简介grpc_zap日志记录grpc_auth认证grpc_recovery恢复总结前言 之前介绍了gRPC中TLS认证和自定义方法认证,...
    99+
    2022-11-13
  • Go gRPC进阶教程gRPC转换HTTP
    目录前言gRPC转成HTTP编写和编译proto服务端代码修改使用postman测试生成swagger文档把swagger-ui转成Go代码,备用对外提供swagger-ui在swa...
    99+
    2022-11-13
  • Go gRPC进阶教程服务超时设置
    目录前言客户端请求设置超时时间服务端判断请求是否超时运行结果总结前言 gRPC默认的请求的超时时间是很长的,当你没有设置请求超时时间时,所有在运行的请求都占用大量资源且可能运行很长的...
    99+
    2022-11-13
  • Go gRPC服务proto数据验证进阶教程
    目录前言创建proto文件,添加验证规则把grpc_validator验证拦截器添加到服务端其他类型验证规则设置总结前言 上篇介绍了go-grpc-middleware的grpc_z...
    99+
    2022-11-13
  • Go gRPC服务双向流式RPC教程
    目录前言情景模拟新建proto文件创建Server端创建Client端总结前言 上一篇介绍了客户端流式RPC,客户端不断的向服务端发送数据流,在发送结束或流关闭后,由服务端返回一个响...
    99+
    2022-11-13
  • Go gRPC服务端流式RPC教程示例
    目录前言情景模拟:实时获取股票走势新建proto文件创建Server端创建Client端思考总结前言 上一篇介绍了简单模式RPC,当数据量大或者需要不断传输数据时候,我们应该使用流式...
    99+
    2022-11-13
  • Go gRPC服务客户端流式RPC教程
    目录前言情景模拟:客户端大量数据上传到服务端新建proto文件创建Server端创建Client端思考总结前言 上一篇介绍了服务端流式RPC,客户端发送请求到服务器,拿到一个流去读取...
    99+
    2022-11-13
  • 基于微服务框架go-micro开发gRPC应用程序
    go-micro是golang的一个微服务框架。这篇文章将介绍使用go-micro最新版本v4开发gRPC服务的方式。 1、安装protoc 这个工具也称为proto编译器,可以用来...
    99+
    2022-11-13
  • vuex学习进阶篇之getters的使用教程
    目录1.设置gettes 事件2.使用调用3.最终页面示例getters的优点:总结紧接上篇,本片主要讲讲vuex 中 getters的使用,示例中使用了vuex的modules,g...
    99+
    2022-11-13
    vuex getters使用 vuex状态管理getters
  • 【MySQL进阶教程】 索引使用与设计原则
    前言 本文为 【MySQL进阶教程】 索引使用与设计原则 相关知识,下边将对索引的使用(包括:验证索引效率,最左前缀法则,范围查询,索引失效情况,SQL提示,覆盖索引,前缀索引,单列索引与联合索引)...
    99+
    2023-09-29
    mysql 数据库 java
  • 云服务器ecs使用教程
    云服务器(Cloud Storage,也称为云存储)是一种基于互联网的服务器软件,常常用于存储大量文件、数据和应用程序,它们通过远程访问协议(RDP)进行连接。在云服务器中,用户可以使用公共云账户(如Amazon Cloud Direct或...
    99+
    2023-10-25
    服务器 教程 ecs
  • windows云服务器使用教程
    Windows云服务器是一种可以将您的文件和应用程序存储在云端的服务。以下是一些云服务器需要知道的基本概念和使用教程:数据库 云服务器提供了一个云端的数据库,可以让您轻松地查询、管理和共享文件和应用程序数据。您可以选择将文件和应用程序存储在...
    99+
    2023-10-25
    服务器 教程 windows
  • 云服务器API使用教程
    1. 什么是云服务器API? 云服务器API(Application Programming Interface)是一组定义了云服务器服务功能和操作的接口。通过使用API,开发人员可以与云服务器进行交互,实现自动化管理和控制。 2. 获取...
    99+
    2023-10-27
    服务器 教程 API
  • 云服务器的使用教程
    云服务器是一种虚拟的、可伸缩的、高可用性的计算资源,可以按需提供并快速扩展。下面是一些基本的云服务器使用教程:创建一个Web服务器,用于存储数据,如图片、PDF等。配置您的云服务器,包括CPU、内存、磁盘空间等参数。创建一个P2P网络,使用...
    99+
    2023-10-25
    服务器 教程
  • 怎么使用云服务器进行多开游戏教程
    使用云服务器进行多开游戏的步骤如下: 下载并安装云服务器:首先,您应该下载并安装云服务器的基础软件,例如CloudApp,PeerSuite等等。在此过程中,您可能会遇到不同的软件版本和安装路径,因此需要仔细查看相应的说明。 启用服务器...
    99+
    2023-10-26
    服务器 教程 游戏
  • 怎么使用云服务器进行多开操作教程
    使用云服务器进行多开操作非常简单。以下是一些基本的步骤: 下载和安装云服务器。首先,您需要安装一个云服务器的管理器(例如Salesforce,AWS等)。在开始使用云服务器之前,请确保您已经安装了您的操作系统和应用程序。 创建一个虚拟账...
    99+
    2023-10-26
    操作 服务器 教程
  • 华为云服务器使用教程
    华为云服务器是华为公司的一种云服务,可以通过华为云应用商店下载安装。以下是安装华为云服务器的教程步骤:需要注意的是,华为云服务器支持多个操作系统,因此您需要安装多个操作系统才能同时使用华为云服务器的多个功能。...
    99+
    2023-10-26
    华为 服务器 教程
  • 腾讯云服务器使用教程
    腾讯云服务器是一款功能强大、稳定可靠的云计算服务平台,可以帮助用户实现快速部署,并提供稳定、高效的基础设施服务。以下是腾讯云服务器使用教程: 选择云服务器提供商:在选购云服务器时,需要了解该提供商的品牌、规模、历史、服务等信息。可以通过...
    99+
    2023-10-26
    腾讯 服务器 教程
  • 云服务器使用方法教程
    云服务器是一种虚拟服务器软件,通过网络提供计算服务,可以通过互联网访问。下面是云服务器的使用方法教程: 下载云服务器的软件并使用。您可以在网站上或通过其他在线服务搜索云服务器并下载软件。 启动和运行云服务器。如果您已经下载了云服务器的软...
    99+
    2023-10-26
    使用方法 服务器 教程
  • 亚马逊服务器使用教程
    1. 注册亚马逊 AWS 账号 首先,你需要注册一个亚马逊 AWS(Amazon Web Services)账号。访问 AWS 官方网站(https://aws.amazon.com/),点击 "创建 AWS 账号" 按钮,然后按照指示填...
    99+
    2023-10-27
    亚马逊 服务器 教程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作