题记
这是我参与「第五届青训营 」伴学笔记创作活动的第 13天,本文用于记录在青训营的学习笔记和一些心得。
day13 1月27日
Hertz
基本实现
使用该命令安装hz工具go install github.com/cloudwego/hertz/cmd/hz@latest,然后hz new
生成基本结构。运行main.go(main.go里面的main内容需要修改过)
运行之后没有报错,打开终端输入以下命令curl http://127.0.0.1:8888/ping,如果状态码是200说明基本没啥问题。
使用Hertz实现,服务监听8080端口并注册了一个GET方法的路由函数。
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等方法用于注册路由。
路由组
hertz提供了路由组(Group)的能力,用于支持路由分组的功能。(注意中间件也可以注册到路由组上——>路由组中间件)
例子:如果你要访问v1.get(),那么你应该输入的url是:http://127.0.0.1:8080/v1/get
当然你也可以这样分组
路由
Hertz 支持丰富的路由类型用于实现复杂的功能,包括静态路由、参数路由、通配路由。
路由的优先级:静态路由 > 命名路由 > 通配路由
静态路由:上面的都算是静态路由了。
参数路由:Hertz 支持使用 :name 这样的命名参数设置路由,并且命名参数只匹配单个路径段。如果我们设置/user/:name路由,匹配情况如下
| 路径 | 是否匹配 |
|---|---|
| /user/gordon | 匹配 |
| /user/you | 匹配 |
| /user/gordon/profile | 不匹配 |
| /user/ | 不匹配 |
通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。
通配路由:Hertz 支持使用 *path 这样的通配参数设置路由,并且通配参数会匹配所有内容。如果我们设置/src/*path路由,匹配情况如下
| 路径 | 是否匹配 |
|---|---|
| /src/ | 匹配 |
| /src/somefile.go | 匹配 |
| /src/subdir/somefile.go | 匹配 |
通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。
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-data 或 application/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 处理作为兜底。
BindAndValidate将来自*RequestContext的数据绑定到obj,并在需要时对其进行验证。注意:obj应该是指针。
Hertz中间件
Hertz中间件的种类是多种多样的,简单分为两大类:
- 服务端中间件
- 客户端中间件
定义一个中间件,返回值一定要是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.example
struct 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复用对象协议层数据解析优化