day13 初识Hertz|青训营笔记

339 阅读5分钟

题记

这是我参与「第五届青训营 」伴学笔记创作活动的第 13天,本文用于记录在青训营的学习笔记和一些心得。

day13 1月27日

Hertz

基本实现

使用该命令安装hz工具go install github.com/cloudwego/hertz/cmd/hz@latest,然后hz new

生成基本结构。运行main.go(main.go里面的main内容需要修改过)image-20230127151209498

运行之后没有报错,打开终端输入以下命令curl http://127.0.0.1:8888/ping,如果状态码是200说明基本没啥问题。

image-20230127151432108

使用Hertz实现,服务监听8080端口并注册了一个GET方法的路由函数。

image-20230127200438382

server.Default:Default创建一个hertz实例,自带默认的中间件。如果不想用自带的默认中间件,你可以使用server.New自定义中间件。

server.withHostPorts:设置监听地址。

Get:h.GET()是类似于一个路由处理器,传入二个参数,相关路径(RelativePath)、处理函数(handle function)。

h.Spin:运行服务直到出现error或者是os.Signal,也就是它之后的代码是不运行的。

context.Context:Package context 中定义了 Context 类型, 用于跨 API 或跨进程之间传递数据,包含 deadlines, cancellation signals, 以及其他 request-scoped values 。对服务器的传入请求应该创建一个Context上下文,对服务器的传出调用应该接受一个Context上下文。它们之间的函数调用链必须传播 Context,可选择将其替换为使用 WithCancel、WithDeadline、WithTimeout 或 WithValue 创建的派生 Context。当一个上下文 Context 被取消时,所有从它派生的上下文也被取消。

*app.RequestContex:是个请求上下文,专注获取请求信息的。

consts.StatusOK:200

ctx.JSON:jSON 将给定的结构序列化为 JSON 到响应主体中。 它还将 Content-Type 设置为“application/json”。

utils.H:H is a shortcut for map[string]interface{}

方法

Hertz提供了GET、POST、PUT、DELETE、ANY等方法用于注册路由。

image-20230127202458303

路由组

hertz提供了路由组(Group)的能力,用于支持路由分组的功能。(注意中间件也可以注册到路由组上——>路由组中间件

image-20230127203032440

例子:如果你要访问v1.get(),那么你应该输入的url是:http://127.0.0.1:8080/v1/get

当然你也可以这样分组

image-20230127203240827

路由

Hertz 支持丰富的路由类型用于实现复杂的功能,包括静态路由、参数路由、通配路由。

路由的优先级:静态路由 > 命名路由 > 通配路由

静态路由:上面的都算是静态路由了。

参数路由:Hertz 支持使用 :name 这样的命名参数设置路由,并且命名参数只匹配单个路径段。如果我们设置/user/:name路由,匹配情况如下

路径是否匹配
/user/gordon匹配
/user/you匹配
/user/gordon/profile不匹配
/user/不匹配

通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。

image-20230127203912016

image-20230127203900484

通配路由:Hertz 支持使用 *path 这样的通配参数设置路由,并且通配参数会匹配所有内容。如果我们设置/src/*path路由,匹配情况如下

路径是否匹配
/src/匹配
/src/somefile.go匹配
/src/subdir/somefile.go匹配

通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。

image-20230127204116244

image-20230127204102848

hertz参数绑定

支持的 tag

go tag说明
path绑定 url 上的路径参数,相当于 hertz 路由{:param}或{*param}中拿到的参数。例如:如果定义的路由为: /v:version/example,可以把 path 的参数指定为路由参数:path:"version",此时,url: http://127.0.0.1:8888/v1/example,可以绑定path参数"1"
form绑定请求的 body 内容。content-type -> multipart/form-dataapplication/x-www-form-urlencoded,绑定 form 的 key-value
query绑定请求的 query 参数
header绑定请求的 header 参数
json绑定请求的 body 内容 content-type -> application/json,绑定 json 参数
raw_body绑定请求的原始 body(bytes),绑定的字段名不指定,也能绑定参数。(注:raw_body 绑定优先级最低,当指定多个 tag 时,一旦其他 tag 成功绑定参数,则不会绑定 body 内容。)
vd参数校验,校验语法

参数绑定优先级

path > form > query > cookie > header > json > raw_body

注:如果请求的 content-type 为 application/json,那么会在参数绑定前做一次 json unmarshal 处理作为兜底。

image-20230127204916403

BindAndValidate将来自*RequestContext的数据绑定到obj,并在需要时对其进行验证。注意:obj应该是指针。

Hertz中间件

Hertz中间件的种类是多种多样的,简单分为两大类:

  • 服务端中间件
  • 客户端中间件

image-20230127205753713

定义一个中间件,返回值一定要是app.HandlerFunc,使用前打印一句话,调用下一个中间件,再次打印一句话(洋葱模型)。这个代码中是全局中间件(h.Use(中间件))

中间件会按定义的先后顺序依次执行,如果想快速终止中间件调用,可以使用以下方法,注意当前中间件仍将执行

  • Abort():终止后续调用
  • AbortWithMsg(msg string, statusCode int):终止后续调用,并设置 response中body,和状态码
  • AbortWithStatus(code int):终止后续调用,并设置状态

如果访问路由404,注册在路由组的中间件还会被执行吗?应该是不执行的,我看Gin是不执行的。

Client

client.NewClient():创建一个Client

context.Background():标准上下文

client的get或者post请求返回三个参数:status, body,error。

client的get或者post请求传入的第二个参数是dst:当我们需要做高性能开发的时候,我们需要一些结构体是复用的,我们可以传入一段字节数组。

postArgs.Set:post的数据值设置???

func Get() {
    c, err := client.NewClient()
    if err != nil {
        return
    }
    status, body, _ := c.Get(context.Background(), nil, "http://www.example.com")
    fmt.Printf("status=%v body=%v\n", status, string(body))
}
func Post() {
    c, err := client.NewClient()
    if err != nil {
        return
    }
​
    var postArgs protocol.Args
    postArgs.Set("arg", "a") // Set post args
    status, body, _ := c.Post(context.Background(), nil, "http://www.example.com", &postArgs)
    fmt.Printf("status=%v body=%v\n", status, string(body))
}
hz命令行工具

创建新项目

// GOPATH 下执行,go mod 名字默认为当前路径相对GOPATH的路径,也可自己指定
hz new

基于 thrift IDL 创建项目,在当前目录下创建 thrift idl 文件

// idl/hello.thrift
namespace go hello.examplestruct HelloReq {
    1: string Name (api.query="name"); // 添加 api 注解为方便进行参数绑定
}
​
struct HelloResp {
    1: string RespBody;
}
​
​
service HelloService {
    HelloResp HelloMethod(1: HelloReq request) (api.get="/hello");
}
​
hz new -idl idl/hello.thrift
hertz性能

1.网络库Netpoll:在小包的场景下优于标准库。(在https下不支持trs,要修改默认配置为标准库)

2.Json编解码Sonic

3.使用sync.Pool复用对象协议层数据解析优化

生态

image-20230127211703617