大项目制作过程记录 | 青训营笔记

66 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天

如何从0制作一个微服务框架的service模块

制作步骤

【注意import的格式】我们默认的根目录为github.com/xiaohei366/TinyTiktok/,在开发过程中,后面直接加相对路径!

以我的user为例:

  • 首先写好user的idl文件,对应暴露的接口和服务。随后在cmd文件夹下,创建自己模块的文件夹,并通过定义好的idl文件来自动的生成服务端的微服务框架。

    • kitex -module github.com/xiaohei366/TinyTiktok -service UserService -I ./../../idl ./../../idl/UserServer.proto

    • 但是为了下次update生成时,需要重复的定义行为,我们将另外在该文件夹下面创建实质的逻辑函数

  • 在相应的cmd文件夹下的文件夹内,添加三个文件夹

    • service--处理微服务的运行逻辑,该文件夹下创立两个文件夹,本地直接创建{{servicename.go}}来处理不同的逻辑(注意创建完,需要添加到handler.go文件中)

      • dal---处理底层数据库函数
      • pack---处理数据库提取后的拼接格式化函数
    • initialize--进行各种初始化的操作

    • config--存放全局常量、配置微服务所需的结构体等...

  • 先写生成框架的main函数

    • 根据初始化,完成数据库的init和全局常量的config的书写以及initialize文件夹下的书写(若需要调用人家的服务,记得也初始化上rpc)
    • 随后初始化注册中心并打开服务器
  • 随后书写handler.go(因为是自动生成,因此在这里不主动处理逻辑),主要是逻辑外的格式校验与响应返回

    • 这里的书写也将意味着需要对service中的pack里面的响应做一个方法的封装(例如,对通用响应体(code+message)的方法封装)
  • 这个过程中,因为要书写响应,因此会一步步地完善dal(存放对数据库的操作)、pack(对于handle中响应报文的拼接操作)、service(主要动作逻辑)中的内容。这三部分写完,则代表着整个服务已经完成,但是目前还不可以测试,我们需要完成与主api-server的对接

    • 这一步在书写时,可以参考easy-note项目中的note部分,你负责的模块有可能需要用到其他人的函数,这时候自行在模块的根目录(例如我是cmd/user)下创建rpc文件夹书写即可。
    • 顺序大概为首先书写dal层、随后写service,最后在pack里写好封装,不全handler即可!
  • 首先,在cmd/api/biz/rpc下的创建自己模块的go文件(勿忘在init.go进行注册),并根据cmd/api/biz/handler/ApiServer/api_service.go中你负责的接口结构体的所需的数据选择自己微服务服务器开放的响应接口函数,完成初始化。

    • 注意,为了完全解耦,同时保持rpc客户服务端接口的一致性。因此,我们需要将自己模块中的kitex_gen文件夹下的服务文件复制一份到cmd/api/biz/kitex_gen/UserServer。
    • 复制时,需要同时修改如下图所示的文件夹下的四个文件的import路径,改至api路径下。
    • 初始化工作对照自己模块的handler--书写rpc接口
  • 这里插入一小条~,我去搞jwt的初始化去了!

  • cmd/api/biz/router/ApiServer/middleware.go中设置JWT中间件,这一步主要是JWT鉴权你的token,并允许你使用token中携带的信息(如何使用看注意事项)

    • 其各个函数对应的路由中间件,可以对照cmd/api/biz/router/ApiServer/middleware.go
    // use jwt mw
    mw.JwtMiddleware.MiddlewareFunc()
  • 最后去cmd/api/biz/handler/ApiServer/api_service.go,书写你服务的处理逻辑。

    • 这里为了方便封装响应报文对应的状态码---特意增加了一个pack.go函数,从里面可以定义你服务的响应报文格式。

注意事项

  • 在请求方request的接口中,不需要定义token字段,因为JWT会帮我们处理好(取而代之的就是设置JWT中间件),可以通过下一条注意事项直接从api服务端获得id传给微服务端,因此若请求只有一个token, 则把他直接换为id即可

  • 如何在token中携带信息?如何提取jwt中token中携带的信息

    • 首先要像note项目中,在中间件部分加入鉴权mw.JwtMiddleware.MiddlewareFunc(),,这个函数会将信息自动保存在RequestContext

    • cmd/api/biz/middleware/jwt.go中的IdentityHandler以及PayloadFunc负责将信息注入app.RequestContext中。(但是请注意,默认携带的是userId,如想带其他的,可以联系我修改Authenticator函数的返回值,从而带上其他的信息)

    • LoginResponse: func(ctx context.Context, c *app.RequestContext, code int, token string, expire time.Time) {
                  v, _ := c.Get(shared.IdentityKey) //取出token中储存的信息
                  c.JSON(code, utils.H{
                      "status_code":   errno.Success.ErrCode,
                      "status_msg": "success",
                      "user_id": v.(*api.User).Id,//此处演示如何使用
                      "token":  token,
                  })
              },