2、gateway编写
目录结构
.
├── handlers
│ ├── handle.go
│ └── register.go
├── main.go
└── rpc
├── init.go
└── user.go
handlers对应所有的 http接口
rpc封装了对应需要的所有RPC服务的client端以及相应的请求方法
main.go主要是包含了启动类配置
1、编写RPCclient端
编写RPCclient端,将RPCcall封装为外部可访问函数,借由httphandler调用
-
Init类
启动类封装,封装所有的私有RPC启动类为一个公有方法,供主启动类使用
//init.go package rpc func InitRPC() { initUserRpc() } -
userclient
//user.gp package rpc import ( "context" "easynote/kitex_gen/user" "easynote/kitex_gen/user/userservice" "easynote/pkg/constants" "easynote/pkg/errno" "easynote/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" "time" ) 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.WithMiddleware(middleware.ClientMiddleware), //配置客户端中间件 client.WithMuxConnection(1), //配置最大复用连接数 client.WithRPCTimeout(3*time.Second), //配置RPC请求超时时间 client.WithConnectTimeout(50*time.Second), //配置连接超时时间 client.WithFailureRetry(retry.NewFailurePolicy()), //配置失败重试 client.WithSuite(trace.NewDefaultClientSuite()), //配置链路追踪 client.WithResolver(r), //配置服务发现 ) if err != nil { panic(err) } userClient = c } // 封装PRC请求 func CreateUser(ctx context.Context, req *user.CreateUserRequest)error{ resp,err := userClient.CreateUser(ctx, req) if err !=nil{ return err } if resp.BaseResp.StatusCode != 0{ return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage) } return nil } func CheckUser(ctx context.Context, req *user.CheckUserRequest) (int64,error){ resp, err := userClient.CheckUser(ctx,req) if err != nil{ return 0, err } if resp.BaseResp.StatusCode != 0{ return 0 ,errno.NewErrNo(resp.BaseResp.StatusCode,resp.BaseResp.StatusMessage) } return resp.UserId, nil }
2、编写httpHandler
demo中将每一个业务操作对应一个httphandler,类似web开发的service端,目前还不涉及复杂的业务逻辑,我们就按照demo的方式编写接口
//register
package handlers
import (
"context"
"easynote/kitex_gen/user"
"github.com/gin-gonic/gin"
"net/http"
"easynote/cmd/api/rpc"
"easynote/pkg/errno"
)
// Register register user info 封装为了一个gin handler
func Register(c *gin.Context) {
var registerVar UserParam
if err := c.Bind(®isterVar); err != nil {
Err(c, http.StatusBadRequest, errno.ConvertErr(err), nil)
return
}
if len(registerVar.UserName) == 0 || len(registerVar.PassWord) == 0 {
Err(c, http.StatusBadRequest, errno.ParamErr, nil)
return
}
err := rpc.CreateUser(context.Background(), &user.CreateUserRequest{
UserName: registerVar.UserName,
Password: registerVar.PassWord,
})
if err != nil {
Err(c, http.StatusInternalServerError, errno.ConvertErr(err), nil)
return
}
Success(c, http.StatusOK, errno.Success, nil)
}
3、编写handle类
demo中将前端可能发来的表单页面和封装返回函数放在了一个文件中
//handle.go
package handlers
import (
"context"
"easynote/kitex_gen/user"
"github.com/gin-gonic/gin"
"net/http"
"easynote/cmd/api/rpc"
"easynote/pkg/errno"
)
// Register register user info 封装为了一个gin handler
func Register(c *gin.Context) {
var registerVar UserParam
if err := c.Bind(®isterVar); err != nil {
Err(c, http.StatusBadRequest, errno.ConvertErr(err), nil)
return
}
if len(registerVar.UserName) == 0 || len(registerVar.PassWord) == 0 {
Err(c, http.StatusBadRequest, errno.ParamErr, nil)
return
}
err := rpc.CreateUser(context.Background(), &user.CreateUserRequest{
UserName: registerVar.UserName,
Password: registerVar.PassWord,
})
if err != nil {
Err(c, http.StatusInternalServerError, errno.ConvertErr(err), nil)
return
}
Success(c, http.StatusOK, errno.Success, nil)
}
4、编写主启动类
//main.go
package main
import (
"easynote/cmd/api/handlers"
"easynote/cmd/api/rpc"
"easynote/pkg/constants"
"easynote/pkg/middleware"
"easynote/pkg/tracer"
"github.com/gin-gonic/gin"
)
func Init() {
tracer.InitJaeger(constants.ApiServiceName)
rpc.InitRPC()
}
func main() {
Init()
r := gin.Default()
//分配路由。装配顺序: / + v1/ + user/ + list
ApiGroup := r.Group("/v1/")
//路由分组
user := ApiGroup.Group("/user")
//路由添加,接口多了后可以将路由放入到同一个包中封装
//调用链条
//httpreq-> ginEngine(gateway) -> handlers.Register(controller) -> clientRPCcall -> userServerRecv -> deal -> response ->..
user.POST("/register", handlers.Register)
user.POST("/login", middleware.JWTAuth())
//添加中间件(全局中间件)
ApiGroup.Use(middleware.Cors())
}
err := r.Run(fmt.Sprintf(":%d", 8080))
if err != nil {
panic(err)
}
3、启动gateway与user服务
-
user服务
-
gatewayAPI
4、测试接口
到目前位置,基本的微服务实践就完成了,麻雀虽小,五脏俱全,这里采用了Kitex官方demo easy_note作文蓝本,学习使用Kitex的基本用法以及微服务的开发流程,那么接下来就聚焦到微服务的几个重点元素中一一查看实现原理。