【GO开发工程师】grpc进阶#golang

【GO开发工程师】grpc进阶#golang

推荐个人主页:席万里的个人空间

文章目录

1、protobuf

protobuf 复制代码
syntax = "proto3"; // 指定使用的 protobuf 版本为 proto3
import "google/protobuf/timestamp.proto"; // 导入 Google 提供的时间戳类型定义
option go_package = ".;proto_bak"; // 生成的 Go 语言代码的包名设定为当前目录下的 proto_bak

service Greeter { // 定义一个名为 Greeter 的服务
    rpc SayHello (HelloRequest) returns (HelloReply); // 在 Greeter 服务中定义一个远程过程调用 SayHello,接收 HelloRequest 参数,返回 HelloReply 结果
}

enum Gender { // 定义一个枚举类型 Gender
    MALE = 0; // 枚举值 MALE,值为 0
    FEMALE = 1; // 枚举值 FEMALE,值为 1
}

message HelloRequest { // 定义消息类型 HelloRequest
    string name = 1; // 姓名字段,用于存储姓名信息,字段标签为 1
    string url = 2; // URL 字段,用于存储 URL 信息,字段标签为 2
    Gender g = 3; // Gender 类型的字段,用于存储性别信息,字段标签为 3
    map<string, string> mp = 4; // 字符串键值对映射字段,用于存储键值对信息,字段标签为 4
    google.protobuf.Timestamp addTime = 5; // 时间戳字段,用于存储添加时间信息,字段标签为 5,使用了导入的时间戳类型定义
}

message HelloReply { // 定义消息类型 HelloReply
    string message = 1; // 消息字段,用于存储消息内容,字段标签为 1
}

2、grpc

2.1、gRPC 的 Metadata机制

gRPC 的 Metadata 机制是一种用于在 gRPC 请求和响应中传递元数据的机制。元数据是键值对的集合,可以包含请求的附加信息,比如身份验证凭据、请求标识符、客户端信息等。

在 gRPC 中,元数据可以分为两类:

  1. 请求元数据(Request Metadata):这些是客户端在发起 gRPC 请求时发送的元数据。它们可以用于传递关于请求的附加信息,比如身份验证凭据、请求标识符、客户端信息等。

  2. 响应元数据(Response Metadata):这些是服务端在响应 gRPC 请求时发送的元数据。它们可以用于传递关于响应的附加信息,比如服务端处理结果、附加的状态信息等。

元数据以键值对的形式存在,键是字符串,值可以是任意的序列化数据。在 gRPC 中,元数据通常使用 HTTP/2 格式编码,并在 HTTP/2 标头中传输。

Metadata 机制的使用使得 gRPC 具有灵活的扩展性和自定义能力。开发者可以根据自己的需求,在请求和响应中传递任意类型的元数据,以实现各种功能,比如身份验证、流量控制、跟踪、日志记录等。

2.2、grpc拦截器

我想在每一个 RPC 方法的前面或后面做某些操作,我想针对某个业务模块的 RPC 方法进行统一的特殊处理,我想对 RPC 方法进行鉴权校验,我想对 RPC 方法进行上下文的超时控制,我想对每个 RPC 方法的请求都做日志记录,怎么做呢?

gRPC 的拦截器(Interceptors)是一种强大的功能,它允许在 gRPC 请求处理过程中注入自定义逻辑,类似于中间件。拦截器可以用于实现各种功能,如身份验证、日志记录、性能监控、流量控制等。在 gRPC 中,拦截器是通过使用 gRPC 的拦截器接口来实现的。

以下是一些常见的 gRPC 拦截器:

  1. 认证拦截器(Authentication Interceptor):用于对 gRPC 请求进行身份验证,以确保请求的安全性和合法性。

  2. 授权拦截器(Authorization Interceptor):用于在请求处理之前验证客户端是否具有执行请求操作的权限。

  3. 日志记录拦截器(Logging Interceptor):用于记录请求和响应的日志,以便进行故障排查、审计和性能分析。

  4. 性能监控拦截器(Performance Monitoring Interceptor):用于监控 gRPC 服务的性能指标,如请求处理时间、请求速率等。

  5. 流量控制拦截器(Traffic Control Interceptor):用于限制客户端请求的速率或配额,以确保服务端不会被过多的请求压力影响。

  6. 异常处理拦截器(Exception Handling Interceptor):用于捕获并处理 gRPC 服务中的异常情况,以提供更好的错误处理和用户体验。

有关go-grpc-middleware的使用:go-grpc-middleware下载地址

MD和拦截器案例

client.go

go 复制代码
package main

import (
	"OldPackageTest/grpc_test/proto" // 导入 protobuf 自动生成的代码包
	"context"                        // 导入 context 包
	"fmt"                            // 导入 fmt 包
	"google.golang.org/grpc"         // 导入 gRPC 包
)

// customCredential 是一个自定义的 gRPC 凭据类型
type customCredential struct{}

// GetRequestMetadata 实现了凭据接口中的 GetRequestMetadata 方法,
// 用于返回请求所需的元数据。
func (c customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	// 返回一个包含应用程序 ID 和密钥的元数据
	return map[string]string{
		"appid":  "101010",
		"appkey": "i am key",
	}, nil
}

// RequireTransportSecurity 实现了凭据接口中的 RequireTransportSecurity 方法,
// 返回该凭据是否需要传输安全性。
func (c customCredential) RequireTransportSecurity() bool {
	return false // 此示例中不需要传输安全性
}

func main() {
	// 创建 gRPC 客户端连接选项数组
	var opts []grpc.DialOption
	// 添加使用不安全连接的 Dial 选项
	opts = append(opts, grpc.WithInsecure())
	// 添加使用自定义凭据的 Dial 选项
	opts = append(opts, grpc.WithPerRPCCredentials(customCredential{}))
	// 连接到 gRPC 服务器
	conn, err := grpc.Dial("127.0.0.1:50051", opts...)
	if err != nil {
		panic(err)
	}
	defer conn.Close() // 延迟关闭连接

	// 创建一个 GreeterClient 实例
	c := proto.NewGreeterClient(conn)
	// 向服务器发送 SayHello 请求,并传递 HelloRequest 参数
	r, err := c.SayHello(context.Background(), &proto.HelloRequest{Name: "bobby"})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message) // 打印服务器返回的消息
}

helloworld.proto

protobuf 复制代码
syntax = "proto3";
option go_package = ".;proto";
service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}
//将 sessionid放入 放入cookie中 http协议
//这个就好比文档,表单验证
message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}
//go语言中是生成一个文件, 也就只有python会生成两个文件

使用protoc生成go文件:

protoc --go_out=./ *.proto

server.go

go 复制代码
package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc/codes" // 导入 gRPC 错误码包
	"google.golang.org/grpc/metadata" // 导入 gRPC 元数据包
	"google.golang.org/grpc/status" // 导入 gRPC 状态包
	"net" // 导入网络包

	"google.golang.org/grpc" // 导入 gRPC 包

	"OldPackageTest/grpc_test/proto" // 导入 protobuf 自动生成的代码包
)

// Server 定义 gRPC 服务端结构体
type Server struct{}

// SayHello 实现了 Greeter 服务中的 SayHello 方法
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,
	error) {
	// 根据请求参数构造响应消息
	return &proto.HelloReply{
		Message: "hello " + request.Name,
	}, nil
}

func main() {
	// 定义拦截器函数
	interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		fmt.Println("接收到了一个新的请求") // 打印日志,表示接收到新的请求
		md, ok := metadata.FromIncomingContext(ctx) // 从上下文中获取请求的元数据
		fmt.Println(md)
		if !ok {
			// 如果无法获取元数据,则返回未认证错误
			return resp, status.Error(codes.Unauthenticated, "无token认证信息")
		}

		var (
			appid  string // 定义应用程序 ID
			appkey string // 定义应用程序密钥
		)

		// 从元数据中提取应用程序 ID 和密钥
		if va1, ok := md["appid"]; ok {
			appid = va1[0]
		}

		if va1, ok := md["appkey"]; ok {
			appkey = va1[0]
		}

		// 检查应用程序 ID 和密钥是否有效,若无效则返回未认证错误
		if appid != "101010" || appkey != "i am key" {
			return resp, status.Error(codes.Unauthenticated, "无token认证信息")
		}

		// 调用 gRPC 处理函数处理请求
		res, err := handler(ctx, req)
		fmt.Println("请求已经完成") // 打印日志,表示请求处理完成
		return res, err
	}

	// 创建 gRPC 服务器,并设置拦截器
	opt := grpc.UnaryInterceptor(interceptor)
	g := grpc.NewServer(opt)

	// 在 gRPC 服务器上注册 Greeter 服务
	proto.RegisterGreeterServer(g, &Server{})

	// 监听指定地址和端口
	lis, err := net.Listen("tcp", "0.0.0.0:50051")
	if err != nil {
		panic("failed to listen:" + err.Error())
	}

	// 启动 gRPC 服务器
	err = g.Serve(lis)
	if err != nil {
		panic("failed to start grpc:" + err.Error())
	}
}
相关推荐
柏箱1 分钟前
PHP基本语法总结
开发语言·前端·html·php
进阶的架构师11 分钟前
互联网Java工程师面试题及答案整理(2024年最新版)
java·开发语言
易辰君13 分钟前
python爬虫 - 深入requests模块
开发语言·爬虫·python
人工智障调包侠13 分钟前
基于深度学习多层感知机进行手机价格预测
人工智能·python·深度学习·机器学习·数据分析
木子020420 分钟前
java高并发场景RabbitMQ的使用
java·开发语言
无夜_20 分钟前
Prototype(原型模式)
开发语言·c++
看到请催我学习21 分钟前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
计算机编程-吉哥1 小时前
计算机毕业设计 基于Python的智能文献管理系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档
python·django·毕业设计·计算机毕业论文·计算机毕业设计选题·软件工程毕业设计论文·文献管理系统
笃励1 小时前
Java面试题二
java·开发语言·python
jyan_敬言1 小时前
【Linux】Linux命令与操作详解(一)文件管理(文件命令)、用户与用户组管理(创建、删除用户/组)
linux·运维·服务器·c语言·开发语言·汇编·c++