Go框架三件套详解(3):Hertz | 青训营笔记

474 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第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))
}

1.5 代码生成

1.6 Hertz性能

1.7 Hertz生态