consul-在项目中使用

一. 在python项目中使用

1.目录存放

创建公共目录存放common/register,创建base.py register.py

 

 2.base.py基础类

import abc


class Resister(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def register(self, name, id, address, port):
        pass

    @abc.abstractmethod
    def deregister(self, service_id):
        pass

    @abc.abstractmethod
    def get_all_service(self):
        pass

    @abc.abstractmethod
    def filter_service(self, f):
        pass

 3. 注册文件consul.py

import requests

from common.register import base
import consul


class ConsulRegister(base.Resister):
    def __int__(self, host, port):
        self.host = host
        self.port = port
        self.c = consul.Consul(host=host, port=port)

    def register(self, name, id, address, port):
        check = {
            "GRPC": f"{address}:{port}",
            "GRPCUseTLS": False,
            "Timeout": "5s",
            "Interval": "5s",
            "DeregisterCriticalServiceAfter": "15s"
        }
        # 注册
        return self.c.agent.service.register(name="user-srv", service_id="user-srv2",
                                             address=address, port=port, tags=["mxshop"], check=check)

    def deregister(self, service_id):
        return self.c.agent.service.deregister(service_id)

    def get_all_service(self):
        return self.c.agent.services()

    def filter_service(self, f):
        url = f"http://{self.host}:{self.port}/v1/agent/services"
        params = {
            "filter": f
        }
        rsp = requests.get(url, params=params).json()
        return rsp

 4. 使用

在server.py中使用

    logger.info(f"服务注册开始")
    register = consul.ConsulRegister(settings.CONSUL_HOST, settings.CONSUL_POST)
    if not register.register(name=settings.SERVICE_NAME, id=settings.SERVICE_NAME, address=args.ip, port=args.port,
                             tags=settings.SERVICE_TAGS):
        logger.info(f"服务注册失败")

        sys.exit(0)
    logger.info(f"服务注册成功")
 

  

添加配置文件内容settings.py

 

# consul的配置
CONSUL_HOST = data["consul"]["host"]
CONSUL_PORT = data["consul"]["port"]

# 服务相关的配置
SERVICE_NAME = data["name"]
SERVICE_TAGS = data["tags"]

 

二. 在go-gin项目中使用

1. 配置文件

在config-debug.yaml中添加配置

consul:
  host: '127.0.0.1'
  port: 8500

 在config/config.go中添加配置

type ConsulConfig struct {
	Host string `mapstructure:"host"`
	Port int    `mapstructure:"port"`
}

type ServerConfig struct {
	Name         string        `mapstructure:"name"`
	Port         int           `mapstructure:"port"`
	UserSrvInfo  UserSrvConfig `mapstructure:"user_srv"`
	JWTInfo      JWTConfig     `mapstructure:"jwt"`
	AliSmsConfig AliSmsConfig  `mapstructure:"sms"`
	RedisConfig  RedisConfig   `mapstructure:"redis"`
	ConsulInfo   ConsulConfig  `mapstructure:"consul"`
}

目录结构

 2. 使用

在api/user.go中添加注册信息

	//从注册中心获取到用户服务的信息
	cfg := api.DefaultConfig()
	//cfg.Address = "192.168.1.103:8500"

	cfg.Address = fmt.Sprintf("%s:%d", global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)

	userSrvHost := ""
	userSrvPost := 0

	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	data, err := client.Agent().ServicesWithFilter(fmt.Sprintf(`Service == "%s"`, global.ServerConfig.UserSrvInfo.Name))
	if err != nil {
		panic(err)
	}
	for _, value := range data {
		userSrvHost = value.Address
		userSrvPost = value.Port
		break
	}

	if userSrvHost == "" {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": "用户服务错误",
		})
	}

 文件全部内容

package api

import (
	"context"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/go-redis/redis/v8"
	"github.com/hashicorp/consul/api"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
	"mxshop-api/user-web/forms"
	"mxshop-api/user-web/global"
	"mxshop-api/user-web/global/reponse"
	"mxshop-api/user-web/middlewares"
	"mxshop-api/user-web/models"
	"mxshop-api/user-web/proto"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func removeTopStruct(fileds map[string]string) map[string]string {
	rsp := map[string]string{}
	for field, err := range fileds {
		rsp[field[strings.Index(field, ".")+1:]] = err
	}
	return rsp
}

func HandleGrpcErrorToHttp(err error, c *gin.Context) {
	//	将GRPC的code转换成HTTP的状态码
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				c.JSON(http.StatusNotFound, gin.H{
					"msg": e.Message(),
				})
			case codes.Internal:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "内部错误",
				})
			case codes.InvalidArgument:
				c.JSON(http.StatusBadRequest, gin.H{
					"msg": "参数错误",
				})
			case codes.Unavailable:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "用户服务不可用",
				})
			default:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "其他错误",
				})
			}
			return
		}
	}
}

func HandleValidatorError(ctx *gin.Context, err error) {
	//定义统一返回的报错处理
	errs, ok := err.(validator.ValidationErrors)
	if !ok {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": err.Error(),
		})
	}
	ctx.JSON(http.StatusBadRequest, gin.H{
		"error": removeTopStruct(errs.Translate(global.Trans)),
	})
	return
}

func GetUserList(ctx *gin.Context) {
	//获取用户列表页的接口
	//ip := "127.0.0.1"
	//port := "50051"

	//从注册中心获取到用户服务的信息
	cfg := api.DefaultConfig()
	//cfg.Address = "192.168.1.103:8500"

	cfg.Address = fmt.Sprintf("%s:%d", global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)

	userSrvHost := ""
	userSrvPost := 0

	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	data, err := client.Agent().ServicesWithFilter(fmt.Sprintf(`Service == "%s"`, global.ServerConfig.UserSrvInfo.Name))
	if err != nil {
		panic(err)
	}
	for _, value := range data {
		userSrvHost = value.Address
		userSrvPost = value.Port
		break
	}

	if userSrvHost == "" {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": "用户服务错误",
		})
	}
	//拨号连接用户RPC服务
	userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", userSrvHost, userSrvPost), grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		zap.S().Errorw("[GetUserList]连接失败【用户服务失败】", "msg", err.Error())
	}

	claims, _ := ctx.Get("claims")
	currentUser := claims.(*models.CustomClaims).ID
	zap.S().Infof("访问用户:%d", currentUser)

	//获取前端用户传递的参数
	pn := ctx.DefaultQuery("pn", "0")
	pnInt, _ := strconv.Atoi(pn)
	pSize := ctx.DefaultQuery("psize", "10")
	pSizeInt, _ := strconv.Atoi(pSize)
	fmt.Println(pSizeInt)
	//生成grpc的client并调用接口
	userSrvClient := proto.NewUserClient(userConn)
	rsp, err := userSrvClient.GetUserList(context.Background(), &proto.PageInfo{
		Pn:    int32(pnInt),
		PSize: int32(pSizeInt),
	})
	if err != nil {
		zap.S().Errorw("[GetUserList]查询用户列表失败")
		HandleGrpcErrorToHttp(err, ctx)
		return
	}
	result := make([]interface{}, 0)
	for _, value := range rsp.Data {
		user := reponse.UserResponse{
			Id:       value.Id,
			NickName: value.NickName,
			BirthDay: reponse.JsonTime(time.Unix(int64(value.BirthDay), 0)),
			//BirthDay: time.Unix(int64(value.BirthDay), 0).Format("2022-01-01"),
			//BirthDay: time.Unix(int64(value.BirthDay), 0),
			Gender: value.Gender,
			Mobile: value.Mobile,
		}
		result = append(result, user)

	}
	ctx.JSON(http.StatusOK, result)
}

func PassWordLogin(ctx *gin.Context) {
	//密码登录的接口
	//1.表单验证, 在forms中定义
	//ctx.JSON(http.StatusOK, "密码登录")
	passWordLoginForm := forms.PassWordLoginForm{}

	//固定格式
	if err := ctx.ShouldBind(&passWordLoginForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}

	if !store.Verify(passWordLoginForm.CaptchaId, passWordLoginForm.Captcha, true) {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"captcha": "验证码错误",
		})
		return
	}

	//拨号连接用户RPC服务
	userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port), grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		zap.S().Errorw("[GetUserList]连接失败【用户服务失败】", "msg", err.Error())
	}
	//生成grpc的client并调用接口
	userSrvClient := proto.NewUserClient(userConn)

	//	登录的逻辑, 查询是否存在,密码是否相等
	if rsp, err := userSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequests{
		Mobile: passWordLoginForm.Mobile,
	}); err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				ctx.JSON(http.StatusBadRequest, map[string]string{
					"mobile": "用户不存在",
				})
			default:
				ctx.JSON(http.StatusBadRequest, map[string]string{
					"mobile": "登录失败",
				})
			}
			return
		}
	} else {
		//	只是查询了用户而已,并没有检查密码
		if passRsp, pasErr := userSrvClient.CheckPassWord(context.Background(), &proto.PasswordCheckInfo{
			Password:          passWordLoginForm.PassWord,
			EncryptedPassword: rsp.PassWord,
		}); pasErr != nil {
			ctx.JSON(http.StatusInternalServerError, map[string]string{
				"password": "登录失败",
			})
		} else {
			if passRsp.Success {
				//生成token
				j := middlewares.NewJWT()
				claims := models.CustomClaims{
					ID:          uint(rsp.Id),
					NickName:    rsp.NickName,
					AuthorityId: uint(rsp.Role),
					StandardClaims: jwt.StandardClaims{
						NotBefore: time.Now().Unix(),               //签名的生效时间
						ExpiresAt: time.Now().Unix() + 60*60*24*30, //30day过期
						Issuer:    "wanghui",
					},
				}
				token, err := j.CreateToken(claims)
				if err != nil {
					ctx.JSON(http.StatusInternalServerError, map[string]string{
						"msg": "生成token失败",
					})
					return
				}

				ctx.JSON(http.StatusOK, gin.H{
					"id":         rsp.Id,
					"nick_name":  rsp.NickName,
					"token":      token,
					"expired_at": time.Now().Unix() + 60*60*24*30*1000,
				})
			} else {
				ctx.JSON(http.StatusBadRequest, map[string]string{
					"msg": "登录失败",
				})
			}

		}

	}
}

func Register(ctx *gin.Context) {
	//	用户注册
	//表单验证, 在forms中定义
	registerForm := forms.RegisterForm{}
	//固定格式
	if err := ctx.ShouldBind(&registerForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}

	//验证码校验
	rdb := redis.NewClient(&redis.Options{
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisConfig.Host, global.ServerConfig.RedisConfig.Port),
	})
	//key , values , 过期时间
	value, err := rdb.Get(context.Background(), registerForm.Mobile).Result()
	if err == redis.Nil {
		fmt.Println("key不存在")
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "验证码错误",
		})
		return
	} else {
		if value != registerForm.Code {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"msg": "验证码错误",
			})
			return
		}
	}

	//拨号连接用户RPC服务
	userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port), grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		zap.S().Errorw("[GetUserList]连接失败【用户服务失败】", "msg", err.Error())
	}
	//生成grpc的client并调用接口
	userSrvClient := proto.NewUserClient(userConn)
	user, err := userSrvClient.CreateUser(context.Background(), &proto.CreateUserInfo{
		NickName: registerForm.Mobile,
		PassWord: registerForm.PassWord,
		Mobile:   registerForm.Mobile,
	})
	if err != nil {
		zap.S().Errorw("[Register]注册【 新建用户失败】失败:%s", err.Error())
		HandleGrpcErrorToHttp(err, ctx)
		return
	}

	//注册成功后,生成token
	j := middlewares.NewJWT()
	claims := models.CustomClaims{
		ID:          uint(user.Id),
		NickName:    user.NickName,
		AuthorityId: uint(user.Role),
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix(),               //签名的生效时间
			ExpiresAt: time.Now().Unix() + 60*60*24*30, //30day过期
			Issuer:    "wanghui",
		},
	}
	token, err := j.CreateToken(claims)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, map[string]string{
			"msg": "生成token失败",
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"id":         user.Id,
		"nick_name":  user.NickName,
		"token":      token,
		"expired_at": time.Now().Unix() + 60*60*24*30*1000,
	})
}

  

 

 

 

 

posted @ 2022-11-08 17:27  wanghhhh  阅读(63)  评论(0)    收藏  举报