Go Web框架 Hertz 快速入门 | 青训营笔记

713 阅读4分钟

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

Hertz[həːts] 是字节跳动开源的 Golang 微服务 HTTP 框架,底层的网络库使用了字节跳动开发的高性能 NIO(Non-blocking I/O)网络库Netpoll,目前也支持切换回官方的网络库。

注:Netpoll目前(2023.1.24)无法在Windows环境下使用,所以Windows用户只能使用官方的网络库。

作为国内的开源框架,文档还是比较友好的。

官方文档:Hertz | CloudWeGo

另外 Hertz 开源于2022年6月(Monday, June 20, 2022),第三届字节青训营貌似并没有相关的课程 。

架构设计

这个图如果只是入门的话,看看就行。这个图的结构是指Hertz本身的架构设计,不是用Hertz开发的项目的架构。

hertz.png

不过倒是可以从图中看出Hertz支持的一些协议(HTTP/3,Websocket等)以及特点。

框架特点

高易用性、高性能、高扩展性、多协议支持、网络层切换的能力等

另外不同于一些公司专门有部门来做开源,字节做的Go框架似乎是先满足字节内部的客制化需求(即公司自己内部的定制化需求),积累到一定体量之后开源出来的。这样也蛮好的,起码代码经过实战检验。

快速开始

准备环境

安装好 Go 语言开发环境即可,最好是最新的稳定版(2023.1.24最新稳定版是 1.19.5)

再次提醒:Hertz 支持 Linux、macOS、Windows 系统,但是 NetPoll 不支持 Windows 系统。

代码生成工具 hz

先确保 GOPATH 环境变量已经被正确地定义(例如 export GOPATH=~/go)并且将$GOPATH/bin添加到 PATH 环境变量之中(例如 export PATH=$GOPATH/bin:$PATH);请勿将 GOPATH 设置为当前用户没有读写权限的目录

Windows下添加环境变量即可,Linux和Mac貌似需要在命令行执行上面的两行命令。

命令行输入命令来安装 hz:go install github.com/cloudwego/hertz/cmd/hz@latest

输入 hz -v 要是有版本信息就是成功了

编写 IDL

这里以 Thrift 作为 IDL。

Thrift IDL 语法可参考官方文档:Thrift interface description language

初学者直接看官方文档可能有点抽象,可以看下这篇文章:Thrift & IDL 介绍

新建一个包 idl,在 idl 里新建一个文件 calc.thrift,编写 IDL。

 namespace go calc
 ​
 struct AddReq {
     1: i64 Num1; // 什么都不写,默认绑定所有位置的参数
     2: i64 Num2;
 }
 ​
 struct AddResp {
     1: i64 Sum;
 }
 ​
 service CalcService {
     AddResp AddMethod(1: AddReq request) (api.post="/add");
 }

生成代码

生成代码并拉取依赖

 hz new -module add -idl idl/calc.thrift
 go mod tidy

后续如果有新的接口或者其他更新内容,可以根据 IDL 更新项目。

 hz update -idl idl/calc.thrift

生成完代码之后可以看到有一个项目根目录下有个 .hz 的文件。

 // Code generated by hz. DO NOT EDIT.
 ​
 hz version: v0.5.2

内容其实没啥,但是使用 hz 更新代码的时候,会去找这个文件。这个文件就相当于是项目生成代码的中心,运行 hz 命令时,要保证命令行所在目录和 .hz 文件所在目录一致。

这个时候会发现,项目的代码都是直接生成在根目录下的,那要是用了微服务架构,想把项目写在 cmd 目录下怎么办呢?

使用 hz new -help 查看相关的命令行参数

 NAME:
    hz new - Generate a new Hertz project
 ​
 USAGE:
    hz new [command options] [arguments...]
 ​
 OPTIONS:
    --idl value [ --idl value ]       Specify the IDL file path. (.thrift or .proto)
    --service value                   Specify the service name.
    --module value, --mod value       Specify the Go module name.
    --out_dir value                   Specify the project path.
    --handler_dir value               Specify the handler path.
    --model_dir value                 Specify the model path.
    --client_dir value                Specify the client path. If not specified, IDL generated path is used for 'client' command; no client code is generated for 'new' command

部分参数这里就直接省略了,主要关注后缀为 _dir 的命令,这些是指定项目生成路径的命令。

  • 比如 out_dir: 指定项目生成路径

这里演示下使用命令行参数指定代码生成路径

 hz new -module calc -idl idl/calc.thrift -out_dir cmd/api

对 IDL 进行修改,添加 Sub 接口

 namespace go calc
 ​
 struct AddReq {
     1: i64 Num1; // 什么都不写,默认绑定所有位置的参数
     2: i64 Num2;
 }
 ​
 struct AddResp {
     1: i64 Sum;
 }
 ​
 ​
 struct SubReq {
     1: i64 Num1; // 什么都不写,默认绑定所有位置的参数
     2: i64 Num2;
 }
 ​
 struct SubResp {
     1: i64 Res;
 }
 ​
 ​
 service CalcService {
     AddResp AddMethod(1: AddReq request) (api.post="/add");
     SubResp SubMethod(1: SubReq request) (api.post="/sub");
 }

更新

 cd cmd/api
 hz update -idl ../../idl/calc.thrift # ../../ 表示当前目录往上两级的目录,这里指项目根目录

最后生成的最终结果如下图

image-20230227232558988.png

补充逻辑并运行

简单添加下 add 的逻辑

 func AddMethod(ctx context.Context, c *app.RequestContext) {
     var err error
     var req calc.AddReq
     err = c.BindAndValidate(&req)
     if err != nil {
         c.String(consts.StatusBadRequest, err.Error())
         return
     }
 ​
     resp := new(calc.AddResp)
     resp.Sum = req.Num1 + req.Num2
 ​
     c.JSON(consts.StatusOK, resp)
 }

在 cmd/api 目录下运行项目

 go run .

使用 Apifox 获取其他方式发送请求

结果如下

image-20230227233202769.png