美文网首页go
高性能 Go HTTP 框架Hertz

高性能 Go HTTP 框架Hertz

作者: 追梦人在路上不断追寻 | 来源:发表于2022-10-26 21:54 被阅读0次

什么是Hertz

Hertz[həːts]是一个用于 Go的高性能高可用性可扩展的HTTP 框架。它旨在为开发人员简化构建微服务。

为什么选择Hertz

Hertz的一大亮点是其极高的性能。您可以通过查看以下有关回显请求的统计信息来对此有所了解。

7741oekd9zp9ha7emsm7.png

另一点是它的易用性,我们将在下面讨论。

如何使用Hertz

在这里,我们将编写一个简单的演示,帮助您熟悉Hertz 框架的基本功能。

安装

在使用 Hertz 之前,您需要设置您的 Golang 开发环境并确保它 >= v1.15。

准备好 Golang 环境后,让我们创建小演示的项目文件夹,该文件夹通常位于$GOPATH/src.

mkdir userdemo
cd userdemo

我强烈推荐使用 Hertz 自带的 Hertz 命令行工具hz

hz是 Hertz 框架提供的用于生成代码的工具。目前,hz可以基于 thrift 和 protobuf 的 IDL 为 Hertz 项目生成脚手架。

您可以参考hz 工具包使用以获取更多信息。

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

如果hz版本信息正确显示如下,那么我们已经完成安装并准备好基本的赫兹开发环境。

hz version v0.2.0

定义 IDL

在本节中,我们将为我们的项目编写 IDL 文件userdemo

hz可以使用 thrift IDL 或 protobuf IDL 生成代码,需要安装合适的编译器thriftgoprotoc。我们将以thrift为例。

让我们创建一个 idl 文件夹并定义user.thrift.

// idl/user.thrift
namespace go user

struct BaseResp {
    1: i64 StatusCode;
    2: string StatusMsg;
    3: string data;
}

struct RegisterRequest {
    1: string Username (api.body="username");
    2: string Password (api.body="password");
}

struct RegisterResponse {
    1: BaseResp BaseResp;
}

struct LoginRequest {
    1: string Username (api.body="username");
    2: string Password (api.body="password");
}

struct LoginResponse {
    1: BaseResp BaseResp;
}

struct InfoRequest {
    1: string Username (api.path="username");
}

struct InfoResponse {
    1: BaseResp BaseResp;
}

service UserService {
    RegisterResponse Register(1: RegisterRequest req) (api.post="/user/register");
    LoginResponse Login(1: LoginRequest req) (api.post="/user/login");
    InfoResponse Info(1: InfoRequest req) (api.get="/user/:username");
}

生成代码

在项目目录下执行以下命令。hz将为我们生成脚手架代码。

hz new -idl idl/user.thrift
go mod tidy

如果修改user.thrift已生成的代码,还可以使用以下命令更新生成的代码。

hz update -idl idl/user.thrift

这是生成的代码的结构及其user.thrift含义。对它的简单理解将帮助您入门。

.
├── biz                               // business layer, which stores business logic related processes
│   ├── handler                       // store handler file
│   │   ├── user                      // user corresponds to the namespace defined in thrift IDL; for protobuf IDL, it corresponds to the last level of go_package
│   │   │   |
│   │   │   |__  user_service.go      // the handler file, the user will implement the method defined by the IDL service in this file, it will search for the existing handler in the current file when "update" command, and append a new handler to the end
│   │   └── ping.go                   // ping handler carried by default, used to generate code for quick debugging, no other special meaning
│   ├── model                         // IDL content-related generation code
│   │   └── user                      // hello/example corresponds to the namespace defined in thrift IDL; for protobuf IDL, it corresponds to the last level of go_package 
│   │         └── user.go             // the product of thriftgo, It contains go code generated from the contents of hello.thrift definition. And it will be regenerated when use "update" command.
│   └── router                        // generated code related to the definition of routes in IDL
│       ├── user                      // hello/example corresponds to the namespace defined in thrift IDL; for protobuf IDL, it corresponds to the last level of go_package
│       │     ├── hello.go            // the route registration code generated for the routes defined in hello.thrift by hz; this file will be regenerated each time the relevant IDL is updated
│       │     └── middleware.go       // default middleware function, hz adds a middleware for each generated route group by default; when updating, it will look for the existing middleware in the current file and append new middleware at the end
│       └── register.go               // call and register the routing definition in each IDL file; when a new IDL is added, the call of its routing registration will be automatically inserted during the update; do not edit
├── go.mod                            // go.mod file, if not specified on the command line, defaults to a relative path to GOPATH as the module name
├── idl                               // user defined IDL, location can be arbitrary
│   └── user.thrift
├── main.go                           // program entry
├── router.go                         // user defined routing methods other than IDL
└── router_gen.go                     // the route registration code generated by hz, for calling user-defined routes and routes generated by hz

使用中间件

Hertz 支持许多常用的中间件。在这种情况下,我们将使用Session 中间件来帮助我们计算用户登录的次数。

如前所述,hz帮助我们搭建了大量的脚手架代码。我们只需要关注业务代码。要使用 Session 中间件,您只需要简单地修改如下_loginMw方法middleware.go

func _loginMw() []app.HandlerFunc {
   // your code...
   return []app.HandlerFunc{
      // use session middleware
      sessions.Sessions("usersession", cookie.NewStore([]byte("secret"))),
   }
}

嗯,这不是很容易吗?

改进处理程序

接下来我们将编写处理程序,特别是user_service.go文件。

Hertz 负责数据绑定的简单验证和一些杂务。我们需要做的就是处理请求。

  • 我们先来看看Register方法。

PostForm我们可以通过该方法从 Post 请求表单中接收数据。您还可以使用StringorJSON方法向客户端返回字符串或 JSON 数据,并指定响应状态码。

// Register .
// @router /user/register/ [POST]
func Register(ctx context.Context, c *app.RequestContext) {
   var err error
   var req user.RegisterRequest
   err = c.BindAndValidate(&req)
   if err != nil {
      c.String(400, err.Error())
      return
   }

   resp := new(user.RegisterResponse)

   username := c.PostForm("username")
   password := c.PostForm("password")

   if dal.CheckUsername(username) {
      dal.CreateUser(username, password)

      resp.BaseResp = &user.BaseResp{
         StatusCode: 0,
         StatusMsg:  "register success",
      }

      c.JSON(200, resp.BaseResp)
      return
   }

   resp.BaseResp = &user.BaseResp{
      StatusCode: 1,
      StatusMsg:  "register failed",
   }
   c.JSON(400, resp.BaseResp)
}

jp836zapmbk8mk0pvlsj.png
  • 接下来,让我们来看看Login方法。

这些方法中的大多数都类似于Register,除了我们使用 Session 中间件,它只是设置来计算不同用户登录的次数。

我们可以使用sessions.Default方法来检索会话对象并使用GetSet方法来编辑存储在会话中的值。

// Login .
// @router /user/login/ [POST]
func Login(ctx context.Context, c *app.RequestContext) {
   var err error
   var req user.LoginRequest
   err = c.BindAndValidate(&req)
   if err != nil {
      c.String(400, err.Error())
      return
   }

   resp := new(user.LoginResponse)

   username := c.PostForm("username")
   password := c.PostForm("password")

   if dal.CheckPassword(username, password) {
      session := sessions.Default(c)
      var count int
      cnt := session.Get(username)
      if cnt == nil {
         count = 0
         dal.SetFrequency(username, count)
      } else {
         count = cnt.(int)
         count++
         dal.SetFrequency(username, count)
      }
      session.Set(username, count)
      _ = session.Save()

      resp.BaseResp = &user.BaseResp{
         StatusCode: 0,
         StatusMsg:  "login success",
      }
      c.JSON(200, resp.BaseResp)
      return
   }

   resp.BaseResp = &user.BaseResp{
      StatusCode: 1,
      StatusMsg:  "login failed",
   }
   c.JSON(400, resp.BaseResp)
}

  • 最后,我们来看看Info方法。

在此方法中,我们使用 Hertz 的参数化路线功能,它允许我们使用命名参数(例如 )指定路线:name,以便该参数与路径段匹配。

我们设置:username参数路由,使用Param方法获取请求路径中的值。

// Info .
// @router /user/:username [GET]
func Info(ctx context.Context, c *app.RequestContext) {
   var err error
   var req user.InfoRequest
   err = c.BindAndValidate(&req)
   if err != nil {
      c.String(400, err.Error())
      return
   }

   resp := new(user.InfoResponse)

   username := c.Param("username")

   frequency := dal.GetFrequency(username)

   resp.BaseResp = &user.BaseResp{
      StatusCode: 0,
      StatusMsg:  "info success",
      Data:       strconv.Itoa(frequency),
   }

   c.JSON(200, resp)
}

其他功能

如果您查看router/user/user.go生成者hz,您会看到 Hertz 自动使用Route Group功能,该功能可以帮助您对复杂的路线进行排序和组织。

当我们使用server.Defaultin 时main.go,Hertz 也默认为我们注册了恢复中间件,它优雅地处理了 panic。

既然我们已经介绍了一些主要的 Hertz 方法以及如何使用它们,我希望这将帮助您快速开始使用 Hertz。

概括

此演示仅涵盖 Hertz 功能的一小部分。您可以查看cloudwego/hertz了解更多信息。我确信文档可以回答您的所有问题。

这个演示的代码在这里

相关文章

网友评论

    本文标题:高性能 Go HTTP 框架Hertz

    本文链接:https://www.haomeiwen.com/subject/mdszzrtx.html