Hertz | 青训营笔记

146 阅读2分钟

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

概述

Hertz 是字节内部的 HTTP 框架,参考了其他开源框架的优势,结合字节跳动内部的需求,具有高易用性、高性能、高扩展性特点。

package main

import(
    "context"
    "github.com/cloudwego/hertz/pkg/app"
    "github.com/cloudwego/hertz/pkg/app/server"
    "github.com/cloudwego/hertz/pkg/common/utils"
    "github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main() {
    h := server.Default (server.WithHostPorts("127.0.0.1:8080"))
    h.GET("/ping",func(c context.Context, ctx*app.RequestContext){
        ctx.JSON(consts.Statusok,utils.H{"ping":"pong"})
    })
    h.Spin()
}

sever.Default 会自动集成中间件 sever.New 没有自动集成的中间件

h.Spin() 开启自旋等待

有钩子函数,可以有效实现业务功能

Hertz 服务器监听 8080 端口。而且hertz是两个上下文。

image.png

Hertz路由

Hertz 提供了 GETPOSTPUTDELETEANY 等方法用于注册路由。

func RegisterRoute(h*server.Hertz){
    h.GET("/get",func(ctx context.Context, c *app.RequestContext){
        c.String(consts.Statusok, "get")
    })
    h.POST("/post",func(ctx context.Context, c *app.RequestContext){
        c . String ( consts . Statusok , " post " )
    })
    h.PUT("/put", func(ctx context.Context, c *app.RequestContext){
        c.String(consts.Statusok, "put")
    })
    h.DELETE("/delete",func(ctx context.Context, c *app.RequestContext){
        c.String(consts.Statusok, "delete")
    })
    h.PATCH("/patch",func(ctx context.Context, c *app.RequestContext){
        c.Stging(consts.Statusok, "patch")
    })
    h.HEAD("/head",func(ctx context.Context, c *app.RequestContext){
        c.String(consts.Statusok, "head")
    })
    h.OPTIONS("/options", func(ctx context.Context, c *app.RequestContext){
        c.String(consts.Statusok, "options")
    })
}

路由组

Hertz 提供了路由组(Group)的能力,用于支持路由分组的功能。也支持参数路由和通配路由。 也支持中间件注册在路由组。

// Simple group: v1
v1 := h.Group("/v1")
// LoginEndpoint is a handler func
{
    v1.POST("/Login",LoginEndpoint)
    v1.POST("/submit",submitEndpoint)
    v1.POST("/streaming_read",readEndpoint)
}
// Simple group: v2
v2 := h.Group("/v2")
{
    V2.POST("/Login",LoginEndpoint)
    v2.POST("/submit",submitEndpoint)
    v2.POST("/streaming_read",readEndpoint)
}

Hertz提供了参数路由(命名路由)和通配路由,路由的优先级为:静态路由>参数路由>通配路由

  • 静态路由:/Login
  • 参数路由:/Del/:id
  • 通配路由:/src/*path

参数绑定与校验

hertz 使用开源库 go-tagexpr 进行参数的绑定及验证。提供了 Bind、Validata、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)

        ...
    })
...
}

Hertz 中间件

服务端中间件

Hertz 服务端中间件是 HTTP 请求-响应周期中的一个函数,提供了一种方便的机制来检查和过滤进入应用程序的 HTTP 请求, 例如记录每个请求或者启用CORS。

image.png

Hertz 提供了常用的 BasicAuth、CORS、JWT等中间件

// 方式一
func MyMiddleware() app.HandlerFunc {
  return func(ctx context.Context, c *app.RequestContext) {
    // pre-handle
    // ...
    c.Next(ctx)
  }
}

// 方式二
func MyMiddleware() app.HandlerFunc {
  return func(ctx context.Context, c *app.RequestContext) {
    c.Next(ctx) // call the next middleware(handler)
    // post-handle
    // ...
  }
}

客户端中间件

客户端中间件可以在请求发出之前或获取响应之后执行:

  • 中间件可以在请求发出之前执行,比如统一为请求添加签名或其他字段。
  • 中间件也可以在收到响应之后执行,比如统一修改响应结果适配业务逻辑。 实现一个中间件
func MyMiddleware(next client.Endpoint) client.Endpoint {
  return func(ctx context.Context, req *protocol.Request, resp *protocol.Response) (err error) {
    // pre-handle
    // ...
    err = next(ctx, req, resp)
    if err != nil {
      return
    }
    // post-handle
    // ...
  }
}

参考