【Go语言实战】 (14) Gin+gRPC 微服务实现备忘录 (上) | 用户模块

写在前面

介于很多同学让我出一下关于gRPC的内容,我就用gRPC把备忘录重新做一遍。

源码地址:

https://github.com/CocaineCong/gRPC-todoList

1. 安装部分

1.1 安装gRPC

go get google.golang.org/grpc
go get google.golang.org/protobuf

1.2 安装protoc

可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

下载proto,我是下载这个的。
在这里插入图片描述

然后解压出来把bin目录放在直接放在系统变量当中

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
验证
在这里插入图片描述

2. 用户模块

2.1 总体项目架构

user/
├── cmd                   // 启动入口
├── config                // 配置文件
├── discovery             // etcd服务注册、keep-alive、获取服务信息等等
├── internal              // 业务逻辑(不对外暴露)
│   ├── handler           // 视图层
│   ├── cache             // 缓存模块
│   ├── repository        // 持久层
│   └── service           // 服务层
│       └──pb             // 放置生成的pb文件
├── logs                  // 放置打印日志模块
├── pkg                   // 各种包
│   ├── e                 // 统一错误状态码
│   ├── res               // 统一response接口返回
│   └── util              // 各种工具、JWT、Logger等等..
├── routes                // http路由模块
└── wrappers              // 各个服务之间的熔断降级

2.2 proto文件定义

  • user/internal/service/pb
syntax="proto3";
package pb;
option go_package = "/internal/service;service";

message UserModel {
    
    
    // @inject_tag: json:"user_id"
    uint32 UserID=1;
    // @inject_tag: json:"user_name"
    string UserName=2;
    // @inject_tag: json:"nick_name"
    string NickName=3;
}

执行

protoc -I internal/service/pb internal/service/pb/*.proto --go_out=plugins=grpc:.

生成 pb.go 文件

  • user/service/pb

定义user模块的请求和返回的结构类型,已经rpc方法。

syntax="proto3";
package pb;
import "userModels.proto";
option go_package = "/internal/service;service";

message UserRequest{
    
    
  // @inject_tag: json:"nick_name" form:"nick_name" uri:"nick_name"
  string NickName=1;
  // @inject_tag: json:"user_name" form:"user_name" uri:"user_name"
  string UserName=2;
  // @inject_tag: json:"password" form:"password" uri:"password"
  string Password=3;
  // @inject_tag: json:"password_confirm" form:"password_confirm" uri:"password_confirm"
  string PasswordConfirm=4;
}

message UserDetailResponse{
    
    
  UserModel UserDetail=1;
  uint32 Code=2;
}

service UserService{
    
    
  rpc UserLogin(UserRequest) returns(UserDetailResponse);
  rpc UserRegister(UserRequest) returns(UserDetailResponse);
  rpc UserLogout(UserRequest) returns(UserDetailResponse);
}

2.3 repository

这一层主要是对持久化的操作,基础的业务操作。

type User struct {
    
    
	UserID         uint      `gorm:"primarykey"`
	UserName       string    `gorm:"unique"`
	NickName       string
	PasswordDigest string
}
  • 视图返回
func BuildUser(item User) *service.UserModel {
    
    
	userModel := service.UserModel{
    
    
		UserID:   uint32(item.UserID),
		NickName: item.NickName,
		UserName: item.UserName,
	}
	return &userModel
}

2.4 接入ETCD服务发现

  • user/cmd/main.go

新建一个etcd节点

etcdAddress := []string{
    
    viper.GetString("etcd.address")}
// 服务注册
etcdRegister := discovery.NewRegister(etcdAddress, logrus.New())
grpcAddress := viper.GetString("server.grpcAddress")

接入user节点

userNode := discovery.Server{
    
    
		Name: viper.GetString("server.domain"),
		Addr: grpcAddress,
	}

节点绑定服务

service.RegisterUserServiceServer(server, handler.NewUserService())

服务注册

if _, err := etcdRegister.Register(userNode, 10); err != nil {
    
    
	panic(fmt.Sprintf("start server failed, err: %v", err))
}

3. 接入网关

3.1 router

  • api-gateway/routes/router.go

引入gin作为http网关

func NewRouter(service ...interface{
    
    }) *gin.Engine {
    
    
	ginRouter := gin.Default()
	ginRouter.Use(middleware.Cors(), middleware.InitMiddleware(service), middleware.ErrorMiddleware())
	store := cookie.NewStore([]byte("something-very-secret"))
	ginRouter.Use(sessions.Sessions("mysession", store))
	v1 := ginRouter.Group("/api/v1")
	{
    
    
		v1.GET("ping", func(context *gin.Context) {
    
    
			context.JSON(200, "success")
		})
		// 用户服务
		v1.POST("/user/register", handler.UserRegister)
		v1.POST("/user/login", handler.UserLogin)
	}
	return ginRouter
}

3.2 网关连接etcd

与user进行连接,获取user服务

userConn, _ := grpc.Dial("127.0.0.1:10001", opts...)
userService := service.NewUserServiceClient(userConn)

3.3 调用服务

  • api-gateway/internal/handler/user.go
func UserRegister(ginCtx *gin.Context) {
    
    
	var userReq service.UserRequest
	PanicIfUserError(ginCtx.Bind(&userReq))
	// 从gin.Key中取出服务实例
	userService := ginCtx.Keys["user"].(service.UserServiceClient)
	userResp, err := userService.UserRegister(context.Background(), &userReq)
	PanicIfUserError(err)
	r := res.Response{
    
    
		Data:   userResp,
		Status: uint(userResp.Code),
		Msg:    e.GetMsg(uint(userResp.Code)),
	}
	ginCtx.JSON(http.StatusOK, r)
}

猜你喜欢

转载自blog.csdn.net/weixin_45304503/article/details/125327278