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

news2024/11/18 13:39:29

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

在这里插入图片描述

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

文章目录

  • 【GO开发工程师】grpc进阶#golang
    • 1、protobuf
    • 2、grpc
      • 2.1、gRPC 的 Metadata机制
      • 2.2、grpc拦截器

1、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

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

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

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())
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1476072.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react-JSX基本使用

1.目标 能够知道什么是JSX 能够使用JSX创建React元素 能够在JSX中使用JS表达式 能够使用JSX的条件渲染和列表渲染 能够给JSX添加样式 2.目录 JSX的基本使用 JSX中使用JS表达式 JSX的条件渲染 JSX的列表渲染 JSX的样式处理 3.JSX的基本使用 3.1 createElement()的问题 A. …

基于Springboot的计算机知识竞赛网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的计算机知识竞赛网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

Python学习 day05(异常、模块导入、包)

异常 为什么要捕获异常 当程序遇到了BUG&#xff0c;如果不对BUG进行手动捕获&#xff0c;那么整个程序就会因为一个BUG而停止运行&#xff0c;这在有些情况下是会造成很大的损失&#xff0c;但是如果我们进行了手动捕获&#xff0c;那么整个程序会继续运行捕获异常的作用在于&…

ubantu与windows文件传输(filezilla)

ubantu与windows文件传输&#xff08;filezilla&#xff09; windowsubantu20.04Fliezilla windows 到官网下载filezilla&#xff1a;https://www.filezilla.cn/&#xff0c;并安装。 ubantu20.04 1、安装vim sudo apt-get install vim2、安装FTP服务 sudo apt-get instal…

【机器人最短路径规划问题(栅格地图)】基于遗传算法求解

基于遗传算法求解机器人最短路径规划问题&#xff08;栅格地图&#xff09;的仿真结果 仿真结果&#xff1a; 路径长度的变化曲线&#xff1a; 遗传算法优化后的机器人避障路径&#xff1a;

Python入门学习:if语句与条件控制--and、or、in、not in详解与实践

Python入门学习&#xff1a;if语句与条件控制–and、or、in、not in详解与实践 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1…

[AIGC] JDK17中的Record类介绍

文章目录 什么是Record类Record类的特点Record类实践 我们都知道&#xff0c;从Java 14开始, JEP 359 推出了一个新的类型声明Record&#xff0c;Record 类型用来模拟不可变的数据结构&#xff0c;它能产生一个类包含一定数量的只读字段。 什么是Record类 在JDK14中引入了一…

jetson nano——编译安装PySide2

目录 1.打开我提供的文件or官网自己下载&#xff08;需对应PyQt5的版本&#xff09;2.解压文件3.进入目录4.安装clang5. 编译安装6.报错: error: ‘NPY_ARRAY_UPDATEIFCOPY’ was not declared in this scope7.又报错&#xff1a;error: ‘NPY_ARRAY_UPDATEIFCOPY’ was not de…

Yapi部署

【GO开发工程师】Yapi部署 推荐个人主页&#xff1a;席万里的个人空间 文章目录 【GO开发工程师】Yapi部署1、Yapi部署 1、Yapi部署 初始化yapi&#xff1a; git clone https://github.com/Ryan-Miao/docker-yapi.git cd docker-yapi docker-compose upyapi启动失败 1.cd进入…

MySQL里的两个“二次”

文章中所有图片均来自网络 一、double write 第一个二次是mysql一个崩溃恢复很重要的特性-重复写入。 doublewrite缓冲区是位于系统表空间中的存储区域&#xff0c;在该区域中&#xff0c;InnoDB会在将页面写入数据文件中的适当位置之前&#xff0c;从InnoDB缓冲池中刷新这些页…

海量物理刚体 高性能物理引擎Unity Physics和Havok Physics的简单性能对比

之前的博客中我们为了绕过ECS架构&#xff0c;相当于单独用Batch Renderer Group实现了一个精简版的Entities Graphics&#xff0c;又使用Jobs版RVO2实现了10w人同屏避障移动。 万人同屏对抗割草 性能测试 PC 手机端 性能表现 弹幕游戏 海量单位同屏渲染 锁敌 避障 非ECS 那么有…

dolphinscheduler海豚调度(三)SQL任务

在之前的博文中&#xff0c;我们已经介绍了DolphinScheduler海豚调度的基本概念和模块&#xff0c;安装部署和元数据切换&#xff0c;以及Shell任务的实践。今天&#xff0c;让我们来深入探讨DolphinScheduler中另一种常见的任务类型&#xff1a;SQL任务。 SQL任务是DolphinSc…

嵌入式学习 Day 26

数组指针和指针数组 &#xff08;题外话&#xff09; 数组指针&#xff1a;数组指针是一种指针&#xff0c;它指向一个数组的首地址。在C语言中&#xff0c;数组名本身就是一个指向数组首地址的指针&#xff0c;因此数组名可以被赋值给指针变量&#xff0c…

07 Qt自绘组件:图片预览小组件ImageViewer

系列文章目录 01 Qt自定义风格控件的基本原则-CSDN博客 02 从QLabel聊起&#xff1a;自定义控件扩展-图片控件-CSDN博客 03 从QLabel聊起&#xff1a;自定义控件扩展-文本控件-CSDN博客 04 自定义Button组件&#xff1a;令人抓狂的QToolButton文本图标居中问题-CSDN博客 0…

使用Jenkins部署前端Vue项目和后端Java服务

Jenkins安装相关插件&#xff0c;供后续使用&#xff08;Dashboard - Manage Jenkins - Plugins&#xff09; Maven Integration plugin https://plugins.jenkins.io/maven-plugin CloudBees Docker Build and Publish pluginhttps://plugins.jenkins.io/docker-build-publish…

Unity中的UI系统之GUI

目录 概述工作原理和主要作用基础控件重要参数及文本和按钮多选框和单选框输入框和拖动条图片绘制和框 复合控件工具栏和选择网络滚动视图和分组窗口 自定义整体样式自定义皮肤样式 概述 什么是UI系统 UI是User Interface&#xff08;用户界面&#xff09;的简称&#xff0c;用…

【pytorch】函数记录

你好你好&#xff01; 以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 torch.sum()torch.argmax()torch.nn.Parametertorch.unbindtorch.optim.Adam()[^adam]torch.cattorch.unsqueeze()torch.normalize()[^l2]torch.eyetorch.mmto…

网站https证书申请方式

网站HTTPS证书&#xff0c;也称为SSL证书或TLS证书&#xff0c;是一种数字证书&#xff0c;用于在用户浏览器与网站服务器之间建立安全的加密连接。当网站安装了HTTPS证书后&#xff0c;用户访问该网站时&#xff0c;浏览器地址栏会显示为"https://"开头&#xff0c;…

NoSQL--虚拟机网络配置

目录 1.初识NoSQL 1.1 NoSQL之虚拟机网络配置 1.1.1 首先&#xff0c;导入预先配置好的NoSQL版本到VMware Workstation中 1.1.2 开启虚拟机操作&#xff1a; 1.1.2.1 点击开启虚拟机&#xff1a; 1.1.2.2 默认选择回车CentOS Linux&#xff08;3.10.0-1127.e17.x86_64) 7 …

微服务架构 SpringCloud

单体应用架构 将项目所有模块(功能)打成jar或者war&#xff0c;然后部署一个进程--医院挂号系统&#xff1b; > 优点: > 1:部署简单:由于是完整的结构体&#xff0c;可以直接部署在一个服务器上即可。 > 2:技术单一:项目不需要复杂的技术栈&#xff0c;往往一套熟悉的…