Go-zero入门使用 | 青训营

80 阅读4分钟

Go-zero入门使用 | 青训营

介绍

go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。

它的优点有:

  • 轻松获得支撑千万日活服务的稳定性
  • 内建级联超时控制、限流、自适应熔断、自适应降载等微服务治理能力,无需配置和额外代码
  • 微服务治理中间件可无缝集成到其它现有框架使用
  • 极简的 API 描述,一键生成各端代码
  • 自动校验客户端请求参数合法性
  • 大量微服务治理和并发工具包

架构图

安装

goctl

goctl 是 go-zero 的内置脚手架,是提升开发效率的一大利器,可以一键生成代码、文档、部署 k8s yaml、dockerfile 等。

按照官方声明,直接在命令行输入如下:

  • 如果 go 版本在 1.16 以前,则使用如下命令安装:

    go get -u github.com/zeromicro/go-zero/tools/goctl@latest
    
  • 如果 go 版本在 1.16 及以后,则使用如下命令安装:

    go install github.com/zeromicro/go-zero/tools/goctl@latest
    

安装完成后,可输入如下命令验证是否成功:

goctl --version

go-zero

下载go-zero的包直接在项目文件下的命令行中输入:

go get -u github.com/zeromicro/go-zero@latest

简单使用

快速生成默认的api服务:

我们可以通过goctl快速生成默认的api服务,只需要在工作目录下命令行输入:

goctl api new greet
cd greet
go mod init
go mod tidy
go run greet.go -f etc/greet-api.yaml

这样我们就简单的快速生成了api服务,默认监听8888端口号(可以在etc/greet-api.yaml下修改配置),这时我们可以通过curl请求:

curl -i http://localhost:8888/from/you

命令行中会输出:

image.png 同时,我们也可以通过使用的编译器插件一键生成服务api: image.png

然后更新go.mod包依赖关系即可。

整个服务目录结构如下所示:

├── etc
│   └── greet-api.yaml              // 配置文件
├── go.mod                          // mod文件
├── greet.api                       // api描述文件
├── greet.go                        // main函数入口
└── internal                        
    ├── config  
    │   └── config.go               // 配置声明type
    ├── handler                     // 路由及handler转发
    │   ├── greethandler.go
    │   └── routes.go
    ├── logic                       // 业务逻辑
    │   └── greetlogic.go
    ├── middleware                  // 中间件文件
    │   └── greetmiddleware.go
    ├── svc                         // logic所依赖的资源池
    │   └── servicecontext.go
    └── types                       // request、response的struct,根据api自动生成,不建议编辑
        └── types.go

根据api生成服务

此外,我们还可以自己写一个api文件,然后通过goctl根据api文件生成相应的代码。

首先,我们在目录下新建一个order.api:

syntax = "v1"
​
info(
    title: "订单api"
    desc: "通过订单的id返回对应的订单信息"
    author: "Tom"
    email: "123456@qq.com"
    version: "v1"
)
​
​
type request {
    OrderId int64 `json:"order_id"`
}
​
type response {
    OrderId int64 `json:"order_id"`       //订单id
    GoodsName string `json:"goods_name"`  //商品名称
}
​
​
@server(
    jwt: Auth
    group: template
)
​
//定义了一个服务叫order-api
service order-api {
    //获取接口的名字叫获取用户信息
    @doc "获取订单信息"
    //对应的hanlder即controller是orderInfo
    @handler orderInfo
    //请求方法是post,路径是/order/order_id,参数是request,返回值是response
    post /order/info (request) returns (response)
    //可以继续定义多个api
}

然后再命令行下输入:

goctl api go -api *.api -dir ./  --style=goZero

这样我们就根据api文件生成了对应的api项目。

同时goland的插件也支持一键生成模板api:

image.png

syntax = "v1"
​
info(
    title: "type title here"
    desc: "type desc here"
    author: "type author here"
    email: "type email here"
    version: "type version here"
)
​
​
type request {
    // TODO: add members here and delete this comment
}
​
type response {
    // TODO: add members here and delete this comment
}
​
@server(
    jwt: Auth
    group: template
)
service template {
    @handler handlerName // TODO: replace handler name and delete this comment
    get /users/id/:userId (request) returns (response)
}
​

修改完相应的代码后,我们右键该api文件自动生成api项目代码:

image.png

项目的目录如下:

image.png 其中,我们首先查看服务下的所有路由,路径在/internal/handler/routes.go:

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
   server.AddRoutes(
      []rest.Route{
         {
            Method:  http.MethodPost,
            Path:    "/order/info",
            Handler: orderInfoHandler(serverCtx),
         },
      },
   )
}
​
func orderInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
   return func(w http.ResponseWriter, r *http.Request) {
      var req types.Request
      if err := httpx.Parse(r, &req); err != nil {
         httpx.ErrorCtx(r.Context(), w, err)
         return
      }
​
      l := logic.NewOrderInfoLogic(r.Context(), svcCtx)
      resp, err := l.OrderInfo(&req)
      if err != nil {
         httpx.ErrorCtx(r.Context(), w, err)
      } else {
         httpx.OkJsonCtx(r.Context(), w, resp)
      }
   }
}

我们根据业务逻辑的需要,修改/internal/logic/orderinfologic.go文件:

func (l *OrderInfoLogic) OrderInfo(req *types.Request) (resp *types.Response, err error) {
   orderId := req.OrderId
   resp = new(types.Response)
   if orderId == 1 {
      resp.GoodsName = "手机"
   } else {
      resp.GoodsName = "电脑"
   }
   resp.OrderId = orderId
​
   return
}

这样,我们就简单是实现了一个通过订单id查询订单信息的接口,自此一个简单的api服务完成。

下面我们通过curl对我们的api服务进行测试:

首先,启动order.go文件,然后我们在命令行中输入:

curl -X POST -H "Content-Type: application/json" http://localhost:8888/order/info -d "{"order_id": 1}"

需要注意,命令行中curl的命令参数中,设置josn格式参数中的""需要前面加上\,否则会报错。

image.png