这是我参与「第五届青训营 」伴学笔记创作活动的第7天。
0、重点
- Gorm(上上篇)
- Kitex(上一篇)
- Hertz
1、Hertz
Hertz是字节内部开源的http框架,参考了其他开源框架的优势,结合字节跳动内部的需求,具有高易用性、高性能、高扩展性等特点。
参考文档:Hertz | CloudWeGo
1.1 安装
具体过程请参考文档
1.2 路由
Hertz提供了多种路由规则,路由的优先级为:静态路由 > 命名路由 > 通配路由。
静态路由
Hertz提供了GET、POST、PUT、DELETE、ANY等方法用于注册路由。
| 方法 | 介绍 |
|---|---|
Hertz.GET | 用于注册 HTTP Method 为 GET 的方法 |
Hertz.POST | 用于注册 HTTP Method 为 POST 的方法 |
Hertz.DELETE | 用于注册 HTTP Method 为 DELETE 的方法 |
Hertz.PUT | 用于注册 HTTP Method 为 PUT 的方法 |
Hertz.PATCH | 用于注册 HTTP Method 为 PATCH 的方法 |
Hertz.HEAD | 用于注册 HTTP Method 为 HEAD 的方法 |
Hertz.OPTIONS | 用于注册 HTTP Method 为 OPTIONS 的方法 |
Hertz.Handle | 这个方法支持用户手动传入 HTTP Method 用来注册方法,当用于注册普通的 HTTP Method 方法时和上述的方法作用是一致的,并且这个方法同时也支持用于注册自定义 HTTP Method 方法 |
Hertz.Any | 用于注册所有 HTTP Method 方法 |
其中,Any 用于注册所有 HTTP Method 方法;Hertz.StaticFile/Static/StaticFS 用于注册静态文件;Handle 可用于注册自定义 HTTP Method 方法。
路由组
Hertz 提供了路由组( Group )的能力,用于支持路由分组的功能,同时中间件也可以注册到路由组上:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main(){
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
v1 := h.Group("/v1")
v1.GET("/get", func(ctx context.Context, c *app.RequestContext) {
c.String(consts.StatusOK, "get")
})
v1.POST("/post", func(ctx context.Context, c *app.RequestContext) {
c.String(consts.StatusOK, "post")
})
v2 := h.Group("/v2")
v2.PUT("/put", func(ctx context.Context, c *app.RequestContext) {
c.String(consts.StatusOK, "put")
})
v2.DELETE("/delete", func(ctx context.Context, c *app.RequestContext) {
c.String(consts.StatusOK, "delete")
})
h.Spin()
}
创建了如下路由:/v1/get,/v1/post,/v2/put,/v2/delete。
参数路由
Hertz 支持使用 :name 这样的命名参数设置路由,并且命名参数只匹配单个路径段。
如果我们设置/user/:name路由,匹配情况如下
| 路径 | 是否匹配 |
|---|---|
| /user/gordon | 匹配 |
| /user/you | 匹配 |
| /user/gordon/profile | 不匹配 |
| /user/ | 不匹配 |
通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。
示例代码:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main(){
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
// This handler will match: "/hertz/version", but will not match : "/hertz/" or "/hertz"
h.GET("/hertz/:version", func(ctx context.Context, c *app.RequestContext) {
version := c.Param("version")
c.String(consts.StatusOK, "Hello %s", version)
})
h.Spin()
}
通配路由
Hertz 支持使用 *path 这样的通配参数设置路由,并且通配参数会匹配所有内容。
如果我们设置/src/*path路由,匹配情况如下
路径 是否匹配 /src/ 匹配 /src/somefile.go 匹配 /src/subdir/somefile.go 匹配 通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。
示例代码:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main(){
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
// However, this one will match "/hertz/v1/" and "/hertz/v2/send"
h.GET("/hertz/:version/*action", func(ctx context.Context, c *app.RequestContext) {
version := c.Param("version")
action := c.Param("action")
message := version + " is " + action
c.String(consts.StatusOK, message)
})
h.Spin()
}
1.3 参数绑定
Hertz 提供了 Bind,Validate,BindAndValidate 函数用于堆参数进行绑定和校验:
func main() {
r := server.New()
r.GET("/hello", func(c context.Context, ctx *app.RequestContext) {
// 参数绑定需要配合特定的go tag使用
type Test struct {
A string `query:"a" vd:"$!='Hertz'"`
}
// BindAndValidate
var req Test
err := ctx.BindAndValidate(&req)
...
// Bind
req = Test{}
err = ctx.Bind(&req)
...
// Validate,需要使用 "vd" tag
err = ctx.Validate(&req)
...
})
...
}
1.4 Client
Hertz提供了 Http Client 用于帮助用户发送 Http 请求,可以在代码的逻辑中请求第三方服务。
例如,使用GET发送一个Http请求:
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))
}
使用POST发送一个Http请求:
func Post() {
c, err := client.NewClient()
if err != nil {
return
}
var postArgs protocol.Args
postArgs.Set("arg", "a") // 发送参数
status, body, _ := c.Post(context.Background(), nil, "http://www.example.com", &postArgs)
fmt.Printf("status=%v body=%v\n", status, string(body))
}