这是我参与「第五届青训营」伴学笔记创作活动的第16天
Hertz是一个基于Golang语言的轻量级Web框架,用于快速构建高性能的Web应用程序和API服务。它的主要特点包括:
- 简单易用:Hertz的API设计简单直观,易于学习和使用。
- 高性能:Hertz基于Golang语言开发,具有卓越的性能表现。
- 轻量级:Hertz的核心代码非常小巧,不依赖任何第三方库。
- 支持路由:Hertz支持路由功能,可以通过不同的URL路径来访问不同的处理程序。
- 中间件:Hertz提供了中间件机制,可以方便地实现各种功能,如日志记录、鉴权、限流等。
官方文档: Hertz | CloudWeGo
0. hertz框架启动服务
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{"message": "pong"})
})
h.Spin()
}
1. hertz路由
Hertz 提供了 GET、POST、PUT、DELETE、ANY 等方法用于注册路由
func main() {
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
//用于注册静态文件
h.StaticFS("/", &app.FS{Root: "./", GenerateIndexPages: true})
h.GET("/hello", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "hello"})
})
h.Spin()
}
Hertz 提供了路由组( Group )的能力,用于支持路由分组的功能,同时中间件也可以注册到路由组上
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 := h.Group("/v1", basic_auth.BasicAuth(map[string]string{"test": "test"}))
v1.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.String(consts.StatusOK,"ping")
})
参数路由
h.GET("/hertz/:version", func(ctx context.Context, c *app.RequestContext) {
// 获取参数路由参数
version := c.Param("version")
c.String(consts.StatusOK, "Hello %s", version)
})
通配路由
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)
})
2. 参数绑定与验证
基本使用示例:
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)
...
})
...
}
支持的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 参数
- json: 绑定请求的 body 内容 content-type ->
application/json,绑定 json 参数
参数绑定优先级
path > form > query > cookie > header > json > raw_body
设置默认值 参数支持 “default” tag 进行默认值的配置,使用方法如下:
// 生成的代码
type UserInfoResponse struct {
NickName string `default:"Hertz" json:"NickName" query:"nickname"`
}
3. 中间件概述
3.1 服务端中间件
Hertz 服务端中间件是 HTTP 请求-响应周期中的一个函数,提供了一种方便的机制来检查和过滤进入应用程序的 HTTP 请求, 例如记录每个请求或者启用CORS。
中间件可以在请求更深入地传递到业务逻辑之前或之后执行:
- 中间件可以在请求到达业务逻辑之前执行,比如执行身份认证和权限认证,当中间件只有初始化(pre-handle)相关逻辑,且没有和 real handler 在一个函数调用栈中的需求时,中间件中可以省略掉最后的
.Next,如图1的中间件 B。 - 中间件也可以在执行过业务逻辑之后执行,比如记录响应时间和从异常中恢复。如果在业务 handler 处理之后有其它处理逻辑( post-handle ),或对函数调用链(栈)有强需求,则必须显式调用
.Next,如图1的中间件 C。
3.1.1 如何实现一个中间件
// 方式一
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
// ...
}
}
3.1.2 终止中间件调用
中间件会按定义的先后顺序依次执行,如果想快速终止中间件调用,可以使用以下方法,注意当前中间件仍将执行。
Abort():终止后续调用AbortWithMsg(msg string, statusCode int):终止后续调用,并设置 response中body,和状态码AbortWithStatus(code int):终止后续调用,并设置状态码
3.1.3 server级别中间件
对整个server生效
h := server.Default()
h.Use(GlobalMiddleware())
3.1.4 路由组级别中间件
对当前路由组生效
h := server.Default()
group := h.Group("/group")
group.Use(GroupMiddleware())
3.1.5 单一路由级别中间件
func PathMiddleware() []app.HandlerFunc {
return []app.HandlerFunc{func(ctx context.Context, c *app.RequestContext) {
fmt.Println("path middleware")
c.Next(ctx)
}}
}
func main() {
h := server.Default(server.WithHostPorts("127.0.0.1:8888"))
h.GET("/path", append(PathMiddleware(),
func(ctx context.Context, c *app.RequestContext) {
c.String(http.StatusOK, "path")
})...)
h.Spin()
}