这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
目录导航:
1. 测试user微服务
2. api层的实现
3. github仓库地址
1.测试user微服务
接上一篇实现了user微服务,并将服务注册到了etcd上。测试为服务业编写一个客户端发现服务并进行rpc调用,新建douyin/test/userRpc.go如下:
package main
import (
"context"
"douyin/kitex_gen/user"
"douyin/kitex_gen/user/userservice"
"douyin/pkg/constants"
"douyin/pkg/middleware"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/pkg/retry"
etcd "github.com/kitex-contrib/registry-etcd"
trace "github.com/kitex-contrib/tracer-opentracing"
"log"
"time"
)
func main() {
r, err := etcd.NewEtcdResolver([]string{constants.EtcdAddress})
if err != nil {
panic(err)
}
c, err := userservice.NewClient(
constants.UserServiceName,
client.WithMiddleware(middleware.CommonMiddleware),
client.WithInstanceMW(middleware.ClientMiddleware),
client.WithMuxConnection(1), // mux
client.WithRPCTimeout(3*time.Second), // rpc timeout
client.WithConnectTimeout(50*time.Millisecond), // conn timeout
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
client.WithSuite(trace.NewDefaultClientSuite()), // tracer
client.WithResolver(r), // resolver
)
if err != nil {
panic(err)
}
req := &user.DouyinUserRegisterRequest{Username: "111111", Password: "124"}
resp, err := c.CreateUser(context.Background(), req)
req1 := &user.DouyinUserLoginRequest{Username: "111111", Password: "124"}
resp1, err := c.CheckUser(context.Background(), req1)
req2 := &user.DouyinUserRequest{UserId: 1, Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjIyOTg3NjkyMjMsImlhdCI6MTY3NjY4OTIyMywiaXNzIjoiZG91eWluIn0.Yot75U-ZZlXwUfaXEEag6A2Vf-U4LL-wO3RKb07KQlA"} //token是复制的注册后返回的token
resp2, err := c.QueryCurUser(context.Background(), req2)
if err != nil {
log.Fatal(err)
}
log.Println(resp)
log.Println(resp1)
log.Println(resp2)
time.Sleep(time.Second)
}
开启user微服务:终端进入/douyin/cmd/user输入以下指令:
bash ./build.sh
bash ./output/bootstrap.sh
提示如下即成功开启微服务:
编译运行userRpc.go,输出以下结果就是成功进行了服务发现并且完成user rpc调用:
2.api层的实现
服务发现&rpc调用
新建douyin/cmd/api/rpc文件夹,文件存放初始化rpc调用的init.go文件以及对外提供rpc调用接口的user.go文件代码如下:
package rpc
import (
"context"
"douyin/kitex_gen/user"
"douyin/kitex_gen/user/userservice"
"douyin/pkg/constants"
"douyin/pkg/errno"
"douyin/pkg/middleware"
trace "github.com/kitex-contrib/tracer-opentracing"
"time"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/pkg/retry"
etcd "github.com/kitex-contrib/registry-etcd"
)
var userClient userservice.Client
func initUserRpc() {
r, err := etcd.NewEtcdResolver([]string{constants.EtcdAddress})
if err != nil {
panic(err)
}
c, err := userservice.NewClient(
constants.UserServiceName,
client.WithMiddleware(middleware.CommonMiddleware),
client.WithInstanceMW(middleware.ClientMiddleware),
client.WithMuxConnection(1), // mux
client.WithRPCTimeout(3*time.Second), // rpc timeout
client.WithConnectTimeout(50*time.Millisecond), // conn timeout
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
client.WithSuite(trace.NewDefaultClientSuite()), // tracer
client.WithResolver(r), // resolver
)
if err != nil {
panic(err)
}
userClient = c
}
// CreateUser create user info
func CreateUser(ctx context.Context, req *user.DouyinUserRegisterRequest) (int64, string, error) {
resp, err := userClient.CreateUser(ctx, req)
if err != nil {
return -1, "", err
}
if resp.BaseResp.StatusCode != 0 {
return -1, "", errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
}
return resp.UserId, resp.Token, nil
}
// CheckUser check user info
func CheckUser(ctx context.Context, req *user.DouyinUserLoginRequest) (int64, string, error) {
resp, err := userClient.CheckUser(ctx, req)
if err != nil {
return -1, "", err
}
if resp.BaseResp.StatusCode != 0 {
return -1, "", errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
}
return resp.UserId, resp.Token, nil
}
// UserInfo user info format
type UserInfo struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
// QuryUser check user info
func QueryUser(ctx context.Context, req *user.DouyinUserRequest) (*UserInfo, error) {
resp, err := userClient.QueryCurUser(ctx, req)
if err != nil {
return nil, err
}
if resp.BaseResp.StatusCode != 0 {
return nil, errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
}
var userInfo UserInfo
userInfo.ID = resp.User.Id
userInfo.Name = resp.User.Name
return &userInfo, nil
}
gin接收参数返回结果
新建douyin/cmd/api/handles文件夹,文件存放接收参数完成rpc调用返回结果的对应功能文件,user服务包括登录login.go,注册register.go,查询用户信息get_cur_user.go,这里举例register.go,其余代码详见文章末尾github仓库。
package handlers
import (
"context"
"douyin/cmd/api/rpc"
"douyin/kitex_gen/user"
"douyin/pkg/errno"
"github.com/gin-gonic/gin"
"log"
)
func Register(c *gin.Context) {
var registerVar UserParam
if err := c.BindQuery(®isterVar); err != nil {
SendUserResponse(c, errno.ConvertErr(err), -1, "")
return
}
log.Print(registerVar)
if len(registerVar.Username) == 0 || len(registerVar.Password) == 0 {
SendUserResponse(c, errno.ParamErr, -1, "")
return
}
userID, token, err := rpc.CreateUser(context.Background(), &user.DouyinUserRegisterRequest{
Username: registerVar.Username,
Password: registerVar.Password,
})
if err != nil {
SendUserResponse(c, errno.ConvertErr(err), -1, "")
return
}
SendUserResponse(c, errno.Success, userID, token)
}
配置路由&开启api服务
douyin/cmd/api下编写main.go,在main.go中配置路由并且开启服务器如下:
package main
import (
"douyin/cmd/api/handles"
"douyin/cmd/api/middleware"
"douyin/cmd/api/rpc"
"douyin/pkg/tracer"
"net/http"
"github.com/cloudwego/kitex/pkg/klog"
"github.com/gin-gonic/gin"
)
func Init() {
// TODO
tracer.InitJaeger("api")
rpc.InitRPC()
}
func main() {
Init()
r := gin.Default()
r.Use(middleware.OpenTracing())
r.Static("/static", "./public")
douyin := r.Group("/douyin")
userGroup := douyin.Group("/user")
userGroup.POST("/login/", handlers.Login)
userGroup.POST("/register/", handlers.Register)
userGroup.GET("/", middleware.AuthMiddleware(), handlers.QueryCurUser)
if err := http.ListenAndServe("0.0.0.0:8080", r); err != nil {
klog.Fatal(err)
}
}
app连接服务端测试
运行douyin/api下的脚本build.shbash ./build.sh 就能开启服务等待客户端抖声app的连接啦:
在app中进行注册用户,注册成功,终端返回如下消息:
这样就完成了用户登录、注册和返回用户信息,如果后续选择社交方向将继续增加用户信息中关注数量和列表等。