【字节青训营-8】:初探字节微服务框架 Hertz 基础使用及进阶(上)

在这里插入图片描述

一、Hertz 概述

Hertz是字节跳动开源的Go微服务HTTP框架,具有高易用性、高性能、高拓展性的一个特点。在设计之初参考了其他开源框架 fasthttp、gin、echo(这些框架加上RPC也可以成为微服务框架) 的优势。

下图是Hertz的一个架构设计。

在Application应用层,可以看到Server和Client,有对应的Handler处理器、绑定、渲染、上下文、服务发现、中间件等。然后紧接着的是路由层,有路由发现这些。然后就是Protocol协议,因为是HTTP框架,所以肯定支持HTTP1/2/3,包括WS。在传输网络层,可以用Netpoll和Go Net。Hz是Hertz的代码生成工具。

在这里插入图片描述

二、Hertz 简单demo

在Goland中创建一个新的项目,然后写入一个main.go的文件来跑个简单案例看看Hertz是什么样的。

我们 写入下列代码,然后在浏览器中打开终端查看对应的结果。

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() //创建一个默认的 HTTP 服务器实例。
	//"/ping":指定路由路径,表示处理 /ping 路径的 GET 请求。
	h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
		//将响应数据以 JSON 格式返回给客户端。
		//使用 utils.H 创建一个 JSON 对象,包含键值对 "message": "pong"。
		ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
	})
	//启动 HTTP 服务器。
	h.Spin()
}

可以看到对应的请求信息如下:

2025/02/05 19:19:54.036401 engine.go:669: [Debug] HERTZ: Method=GET    absolutePath=/ping                     
--> handlerName=main.main.func1 (num=2 handlers)
2025/02/05 19:19:54.042003 engine.go:397: [Info] HERTZ: Using network library=standard
2025/02/05 19:19:54.042599 transport.go:65: [Info] HERTZ: HTTP server listening on address=[::]:8888

第一行信息表示是Hertz框架生成的日志,absolutePath=/ping:表示请求的路径是 /ping。handlerName=main.main.func1:表示处理这个请求的处理器函数是 main.main.func1。这通常是一个匿名函数,定义在 main 包的 main 函数中。

(num=2 handlers):表示这个请求路径 /ping 经过了 2 个处理器(handler)。这可能包括一个默认的中间件和一个具体的请求处理函数。

第二行Using network library=standard:表示 Hertz 框架正在使用标准的网络库(net/http)来处理 HTTP 请求。

第三行HTTP server listening on address=[::]:8888:表示 HTTP 服务器已经开始监听 [::]:8888 地址。[::] 是 IPv6 的通配符地址,表示服务器监听所有可用的网络接口。

我们在控制台中输入命令 curl http://localhost:8888/ping,可以得到下面的信息:

在这里插入图片描述

三、Hertz 客户端

创建一个简单的Hertz客户端,代码如下:

package main

import (
	"context"
	"fmt"
	"github.com/cloudwego/hertz/pkg/app/client"
	"github.com/cloudwego/hertz/pkg/protocol"
)

// 客户端访问下面的server服务端
func performRequest() {
	c, _ := client.NewClient()
	//客户端有请求和响应,所以创建对应的请求和响应
	req, resp := protocol.AcquireRequest(), protocol.AcquireResponse()
	req.SetRequestURI("http://localhost:8080/hello")
	req.SetMethod("GET")
	_ = c.Do(context.Background(), req, resp)     //执行请求
	fmt.Printf("get response: %s\n", resp.Body()) //获得响应的内容
	//status == 200 resp.Body() == []byte("hello hertz")
}

func main() {
	performRequest()
}

main.go中我们写入简单的服务端的响应代码如下。

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.New(server.WithHostPorts(":8080"))
	h.GET("/hello", func(c context.Context, ctx *app.RequestContext) {
		ctx.JSON(consts.StatusOK, "hello hertz")
	})
	h.Spin()
}

先启动main.go,然后再执行客户端,就可以得到返回get response: "hello hertz"

客户端和request都可以启动对应的配置,比如下面的示例。

在这里插入图片描述
发送请求的几种方式有:

//响应会直接写入Response中去,是一个传出参数
func (c *client) Do(ctx content.Context,req *protocol.Request,resp *protocol.Response) error

func (c *client) DoRedirects //请求重定向
示例:err = c.DoRedirects(context.Background(),req,resp,1)
也就是需要设置最大的重定向次数

func (c *client) Get
示例:status,body,err := c.Get(context.Background(),nil,"https://locolhost:8080/ping")

示例:可以传递参数了,所以可以进行的传递参数
func (c *client) Post
c ,err := client.NewClient()
var postArgs protocol.Args
postArgs.Set("name","cloudwego") //设置post参数
status,body,err := c.Post(context.Background(),nil,"http://localhost:8080/hello",&postArgs)

四、Hertz 路由

Hertz提供了GET、POST、PUT、DELETE、ANY等方式用于路由注册:

在这里插入图片描述

除此之外还提供了路由组的概念,也就是支持路由分组,中间件也可以注册到路由组上。

路由分组的作用是系统有很多功能,比如用户模块、订单模块,所以可以对这些模块的路由进行分组。

在这里插入图片描述

路由组中还可以使用中间件,示例代码(使用basic_auth.BasicAuth)如下:

在这里插入图片描述

路由的优先级包括:静态路由 > 命名参数路由 > 通配参数路由,上面的例子都是静态路由。

我们来看看命名参数路由,使用:name的命名参数设置对应的路由,并且命名参数只匹配单个路径段。

如果设置/user/:name路由,匹配情况就是只能匹配对应的单个,比如/user/you是可以匹配成功的,但是/user/you/name这种匹配不成功。

通过RequestContext.Param可以获取到路由中携带的参数。

在这里插入图片描述

通配参数路由,支持*path这样的通配参数设置路由,并且通配参数会匹配所有的内容。

比如设置了/src/*path路由,匹配情况/src/you/you.go也是可以匹配成功的。

通过RequestContext.Param可以获取到路由中携带的参数。依然使用param := c.Param("path)进行提取。

在这里插入图片描述

五、Hertz 网络库

Hertz默认集成了Netpoll和Golang原生网络库Go net,可以根据自己的需要进行选择开发。

对于Server来说,默认使用netpoll,可以通过配置项进行修改。

server.New(server.WithTransport(standard.NewTransporter())
server.New(server.WithTransport(netpoll.NewTransporter())

例如:
h:= server.New(server.WithHostPorts(":8080"),server.WithTransport(standard.NewTransporter())

netpoll目前貌似不支持win,win通过条件编译的时候会自动将网络库切换为Go net网络库。

对于Client来说,可以通过配置项进行修改。

client.NewClient(client.WithTransport(standard.NewDialer())
client.NewClient(client.WithTransport(netpoll.NewDialer())

如果有启动TLS Server(https加密)的需求,可以使用Go net网络库,Netpoll正在实现对TLS的支持。

由于网络库的触发模式的不同,go net为ET模型,netpoll是LT模型。ET模型下,由框架处理Read/write事件,LT模型下,由网络库处理Read/Write事件。

在小包的场景下,由于更优的调度策略LT性能更好。但是大包场景下,由于读写不受框架层的限制,大量数据被读入内存而不能及时处理,可能会造成内存压力。

所以在较大的request size(比方说大于1M)下,推荐使用go net网络库+流式。

其他场景下可以用netpoll网络库。

六、Hertz hz代码生成

使用命令安装hz。

 go install github.com/cloudwego/hertz/cmd/hz@latest

然后终端输入命令hz new就会自动创建文件。

在这里插入图片描述

main中代码如下所示。

在这里插入图片描述
会进行注册,注册的话会在router_gen.go(路由生成文件)中声明。这里使用了router的GeneratedRegister方法。

在这里插入图片描述
在这个文件中又导入了router文件,我们来看看biz路径下的router文件。

在这里插入图片描述
真正的路由定义是在router.go中进行定义的,这里定义的Ping方法会在biz下面的handler中进行定义。

在这里插入图片描述

在这里插入图片描述

七、Hertz Engine

Hertz的路由、中间件、服务启动和退出等重要的方法都是包含在server.Hertz这个核心类型之中的,由route.EnginesignalWaiter组成。

下面是Hertz的定义:

在这里插入图片描述

在这里插入图片描述

通过server.Default()我们可以看到返回的是一个Hertz的类型的引用,而Hertz是一个结构体,核心就是Engine和SignalWaiter。

在这里插入图片描述
一般情况下用Default,default里面可以传过来很多配置选项,这个里面有很多配置。Default里边还调用了New方法。

在这里插入图片描述
default和new的重要区别就是default里边添加了一个中间件,也就是recovery,以后有panic之后可以发现错误。

Hertz提供了Spin函数启动服务器。

和route.Engine中提供的run不同,除非有特殊的需求,不然都是使用Spin函数用于运行服务。在使用服务注册发现的功能的时候,Spin会在服务启动的时候将服务注册进入注册中心(因为是微服务框架,所以有很多注册中心),并且使用signalWaiter检测服务的异常。只有使用Spin来启动服务的时候才能支持优雅退出。

如果调用了run方法,还要调用错误处理,比如下面的示例代码:

h := server.New()
if err := h.Run(); err!=nil{
	panic(err)
}

接下来来看看Engine引擎部分,包含了Engine名称、路由和协议服务器的选项、router前缀树、模版HTML(支持前后端不分离)、网络库选择、链路追踪、协议层、连接池、hook等。

在这里插入图片描述

### Hertz HTTP Framework 使用指南与示例 Hertz 是由 ByteDance 开发并开源的一个高性能 Go 语言 Web 框架,旨在提供更高效的网络服务开发体验。以下是关于如何使用 Hertz 的详细介绍。 #### 安装 Hertz 为了开始使用 Hertz,首先需要安装该库: ```bash go get github.com/cloudwego/hertz ``` #### 创建简单的HTTP服务器 下面是一个创建简单 HTTP 服务器的例子: ```go package main import ( "context" "fmt" "time" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" ) func hello(c context.Context, ctx *app.RequestContext) { ctx.JSON(200, "hello world") } func main() { h := server.Default() h.GET("/hello", hello) h.Spin() } ``` 这段代码定义了一个处理函数 `hello` 和一个路由 `/hello`,当访问此路径时返回 JSON 响应 `"hello world"`[^3]。 #### 中间件支持 Hertz 支持中间件机制来增强请求处理流程的功能。这里展示怎样添加日志记录中间件到应用中: ```go h.Use(func(ctx context.Context, c *app.RequestContext) { startTime := time.Now() c.Next(ctx) endTime := time.Since(startTime) fmt.Printf("Request took %v\n", endTime) }) ``` 上述片段会在每次请求前后打印执行时间信息[^4]。 #### 错误处理 对于错误情况下的优雅响应,可以自定义全局级别的恢复中间件以捕获 panic 并发送合适的客户端消息: ```go h.Use(recovery.Recovery()) ``` 这行配置会自动为整个应用程序注册一个恢复处理器,在发生未预期异常时防止程序崩溃,并向调用方反馈适当的信息[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值