golang入门笔记——Hertz

news2024/11/18 0:40:44

文章目录

  • Hertz介绍
    • 应用层
    • 路由层
    • 协议层
    • 传输层
    • HZ脚手架
  • Hertz的使用
    • 一个简单的案例:利用Hertz监听8080端口并编写/ping的get处理函数
    • Hertz和gin一样,提供了分组路由的功能
    • Hertz路由的匹配优先级:静态路由>命名路由>通配路由
    • 参数绑定:Bind、Validate、BindAndValidate用于参数绑定和校验
    • 中间件
    • HTTP Client
    • Hertz代码生成工具

Hertz介绍

Hertz是字节跳动研发的企业级微服务HTTP框架,具有高易用性、易扩展、低时延等特点。是基于自研网络库Netpoll开发的内部框架Hertz。Hertz框架整体上满足:
1.极致性能优化的问题性
2.面对未来不可控需求的扩展能力,Hertz采用了4层分层设计(应用层、路由层、协议层、传输层),保证各个层级功能内聚,同时通过层级之间的接口达到灵活扩展的目标。整体框架如下图:

image.png

应用层

主要包括与用户直接交互的易用的API,主要包括Server、Client和一些其他通用抽象。Hertz框架最具特点的是处理函数(HandlerFunc)多了一个context上下文,这是在大量的实践过程中发现的,业务方通常需要一个标准的上下文在RPC Client或者日志、Tracing等组件间传递,但由于请求上下文(RequestContext)生命周期局限于一次HTTP请求之内而以上提到的场景往往存在异步的传递和处理, 导致如果直接传递请求上下文,会导致出现一些数据不一致的问题。因此最终增加了一个标准的上下文入参,从根本上解决各种因为上下文生命周期不一致的异常问题,处理函数的格式为:
type HandlerFunc func(c context.Context,ctx *app.RequestContext)

路由层

Hertz在设计路由时,给了用户极高的自由度去注册路由,支持的路由有:支持静态路由、参数路由的注册;支持按优先级匹配,支持路由回溯,支持尾斜线重定向。例如:
1.优先级匹配,如/a/b和/:c/b,同时满足时,优先匹配/a/b
2.路由回溯,如注册/a/b和/:c/d,当匹配/a/d时仍然能够匹配上/:c/d
3.支持尾斜线重定向,如注册/a/b,当匹配/a/b/时重定向到/a/b上

协议层

协议层负责不同协议的实现和扩展。Hertz支持协议的扩展,用户只需要实现下面的接口便可以按照自己的需求在引擎上扩展协议,同时也支持通过ALPN协议协商的方式注册。Hertz首批只开源了 HTTP1 实现,未来会陆续开源 HTTP2、QUIC 等实现。协议层扩展提供的灵活性甚至可以超越 HTTP 协议的范畴,用户完全可以按需注册任意符合自身需求的协议层实现,并且加入到Hertz的引擎中来,同时,也能够无缝享受到传输层带来的极致性能。

传输层

传输层负责底层的网络库的抽象和实现
Hertz支持底层网络库的扩展。Hertz原生完美匹配Netpoll,在时延方面有很多深度的优化,Netpoll对TLS能力的支持有待完善,为此Hertz底层同时支持基于Golang标准网络库的实现适配,同时支持网络库的一键切换,用户可根据自己的需求选择合适的网络库进行替换。如果用户有更加高效的网络库或其他网络库需求,也完全可以根据需求自行扩展。

HZ脚手架

用户可以提供一个IDL,利用命令行工具Hz,一键生成项目脚手架。Hz也支持基于IDL的更新能力,能够基于IDL变动智能地更新项目代码。Hz支持Thrift和Protobuf两种IDL定义。

Hertz的使用

一个简单的案例:利用Hertz监听8080端口并编写/ping的get处理函数

package main

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

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

Hertz和gin一样,提供了分组路由的功能

v1 := h.Group("/v1")
{
   v1.GET("/login", func(c context.Context, ctx *app.RequestContext) {
   })

}
v2 := h.Group("/v2")
{
   v2.GET("/login", func(c context.Context, ctx *app.RequestContext) {

   })
}

Hertz路由的匹配优先级:静态路由>命名路由>通配路由

h.GET("/herz/:version", func(c context.Context, ctx *app.RequestContext) {

})
h.GET("/herz/*action", func(c context.Context, ctx *app.RequestContext) {

})

参数绑定:Bind、Validate、BindAndValidate用于参数绑定和校验

image.png

参数校验:

type InfoRequest struct {
		Name         string   `vd:"($!='Alice'||(Age)$==18) && regexp('\w')"`
		Age          int      `vd:"$>0"`
		Email        string   `vd:"email($)"`
		Phone1       string   `vd:"phone($)"`
		OtherPhones  []string `vd:"range($, phone(#v,'CN'))"`
		*InfoRequest `vd:"?"`
		Info1        *InfoRequest `vd:"?"`
		Info2        *InfoRequest `vd:"-"`
	}

自定义验证函数:

import "github.com/cloudwego/hertz/pkg/app/server/binding"

func init() {
    binding.MustRegValidateFunc("test", func(args ...interface{}) error {
       if len(args) != 1 {
          return fmt.Errorf("the args must be one")
       }
       s, _ := args[0].(string)
       if s == "123" {
          return fmt.Errorf("the args can not be 123")
       }
       return nil
    })
}

参数绑定优先级:
path > form > query > cookie > header > json > raw_body

type Args struct {
   Query      string   `query:"query"vd:"$!='Hertz'"`
   QuerySlice []string `query:"queryslice"`
   Path       string   `path:"path"`
   Header     string   `header:"header"`
   Form       string   `form:"form"`
   Json       string   `json:"json"`
}

func main(){
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
h.POST("v:path/bind", func(c context.Context, ctx *app.RequestContext) {
   var arg Args
   err := ctx.BindAndValidate(&arg)
   if err != nil {
      panic(err)
   }
})
}

中间件

func MyMiddleware() app.HandlerFunc {
   return func(c context.Context, ctx *app.RequestContext) {
      fmt.Println("pre-handle")
      ctx.Next(c)
      fmt.Println("post-handle")
   }
}
func main() {
   h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
   h.Use(MyMiddleware())
}

HTTP Client

Hertz提供了HTTP Client来模拟用户的请求

package main

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

func main() {
   c, err := client.NewClient()
   if err != nil {
      return
   }
   status, body, _ := c.Get(context.Background(), nil, "http://baidu.com")
   fmt.Printf("status:%v body:%v", status, string(body))
   var postArgs protocol.Args
   postArgs.Set("arg", "a")
   status, body, _ = c.Post(context.Background(), nil, "http://baidu.com", &postArgs)
   fmt.Printf("status:%v body:%v", status, string(body))
}

Hertz代码生成工具

编写IDL

namespace go hello.example

struct HelloReq{
    1:string Name (api.query="name");
}

struct HelloResp{
    1:string RespBody;
}

service HelloService{
    HelloResp HelloMethod(1:HelloReq request)(api.get="/hello")
}

利用hz工具生成代码

hz new -module mod_name -idl idl/hello.thrift

生成的代码目录结构

image.png

生成的主要代码:
biz/handler/hello/example/hello_service.go

// Code generated by hertz generator.

package example

import (
   "context"

   "github.com/cloudwego/hertz/pkg/app"
   "github.com/cloudwego/hertz/pkg/protocol/consts"
   example "hertz-demo/biz/model/hello/example"
)

// HelloMethod .
// @router /hello [GET]
func HelloMethod(ctx context.Context, c *app.RequestContext) {
   var err error
   var req example.HelloReq
   err = c.BindAndValidate(&req)
   if err != nil {
      c.String(consts.StatusBadRequest, err.Error())
      return
   }

   resp := new(example.HelloResp)

   c.JSON(consts.StatusOK, resp)
}

biz/router/hello/example/hello.go

// Code generated by hertz generator. DO NOT EDIT.

package Example

import (
   "github.com/cloudwego/hertz/pkg/app/server"
   example "hertz-demo/biz/handler/hello/example"
)

/*
 This file will register all the routes of the services in the master idl.
 And it will update automatically when you use the "update" command for the idl.
 So don't modify the contents of the file, or your code will be deleted when it is updated.
*/

// Register register routes based on the IDL 'api.${HTTP Method}' annotation.
func Register(r *server.Hertz) {

   root := r.Group("/", rootMw()...)
   root.GET("/hello", append(_hellomethodMw(), example.HelloMethod)...)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/174278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SD卡读写实验(SPI模式)

对于 SD 卡的 SPI 模式而言,采用的 SPI 的通信模式为模式 3,即 CPOL1,CPHA1,在 SD 卡 2.0 版本协议中,SPI_CLK 时钟频率可达 50Mhz。SD 卡的 SPI 模式,只用到了 SDIO_D3(SPI_CS)、SD…

16投影矩阵和最小二乘法

投影矩阵和最小二乘法 投影矩阵 **投影矩阵P与向量b相乘将会把投影到的列空间A中。**那么现在我们来考虑两个极端的例子,这两个极端的例子将会加深我们对投影矩阵的理解。 如果b在矩阵A的列空间里,那么 Pb b 如果b垂直于矩阵A的列空间,那…

经典同步问题

同步问题是一个复杂的问题,但是它也有自己的方法去处理、去分析。PV操作系统的解题思路:关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。(从事件的角度分析)整理思路。根据各进程的操作流程确定P、V操作的大致顺序。设置…

Java设计模式-备忘录模式、备忘录模式应用场景是什么、又怎么使用

继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用! 6.11 备忘录模式 6.11.1 定义 又称快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存此状态&…

深入学习Vue.js(十一)内建组件和模块

文章目录KeepAlive组件的实现原理1.KeepAlive组件实现原理2.KeepAlive组件的代码实现(1)shouldKeepAlive(2)keepAliveInstance(3)keptAlive(4)move函数3.include和exclude4.缓存策略…

视频生成动画数据OpenPose+OpenCV

我们只是使用OpenPose,不包括深度学习和代码的部分,会用就OK。 1.打开OpenPose的官网,直接进入安装页面,地址如下: OpenPose: OpenPose Doc - Installation 2.安装的说明,大家要好好看,我们就…

吴恩达机器学习课程笔记:多元梯度下降法

1.吴恩达机器学习课程笔记:多元梯度下降法 笔记来源:吴恩达机器学习课程笔记:多元梯度下降法 仅作为个人学习笔记,若各位大佬发现错误请指正 1.1 多元特征(变量) 每一列代表一个特征,例如&…

【Github CLI】Take GitHub to the command line

目录儿~一、Git、Github、GitLab二、Github CLI——gh2.1 gh简介2.2 gh的使用2.21 Github身份验证(必选)2.22 常用命令(1)在Github仓库中打开当前项目(2)gh配置 gh config(3)克隆仓库…

(16)go-micro微服务jaeger链路追踪

文章目录一 jaeger链路追踪介绍什么是链路追踪:链路追踪主要功能:二 jaeger链路追踪作用三 jaeger链路追踪主要特性四 jaeger链路追踪原理图1.链路调用原理2. 一次调用链分析3.链路追踪存储与调用五 jaeger链路追踪五个重要组件六 jaeger链路追踪安装1.d…

Junit框架

JUnit 是一个 Java 编程语言的单元测试框架。环境配置创建maven项目&#xff0c;导入Junit配置<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency><groupId>org.junit.jupiter</groupId><artifactId&g…

Linux常用命令——tail命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tail 在屏幕上显示指定文件的末尾若干行 补充说明 tail命令用于输入文件中的尾部内容。tail命令默认在屏幕上显示指定文件的末尾10行。如果给定的文件不止一个&#xff0c;则在显示的每个文件前面加一个文件名…

【docker概念和实践 4】 常见命令和案例(1)

一、说明 本篇讲述当Docker安装完成后&#xff0c;进行的由浅入深的操作过程。命令种类有&#xff1a;1 进程引擎进程命令 2帮助命令 3 镜像命令 4 容器命令 5 仓库命令。 二、关于操作引擎的指令 本节讲操作引擎的启动、关闭、维护等。以下两种形势都是等价的命令格式。 方法…

Java概览——Java运行机制

Java概览—Java运行机制Java的运行过程 Java程序运行时&#xff0c;必须经过编译和运行两个步骤。首先将后缀名为.java的源文件进行编译&#xff0c;最终生成后缀名为.class的字节码文件&#xff0c;然后Java虚拟机&#xff0c;将字节码文件进行解释执行&#xff0c;并将结果显…

Docker学习笔记【part1】概念与安装

一、Docker的概念 Docker 是实现系统平滑移植、容器虚拟化的技术&#xff0c;基于 Go语言&#xff0c;可以实现软件带环境安装&#xff0c;做到“一次镜像&#xff0c;处处运行”。Docker 是一个 C/S 模式的架构&#xff0c;后端是一个松耦合架构&#xff0c;众多模块各司其职…

九龙证券|次新股叠加智慧交通+信创+数字经济概念,开盘冲涨停!

核算机板块1月以来跑赢上证指数&#xff1b;才智交通、成绩高增及严重财物重组个股登上涨停榜。 证券时报•数据宝核算&#xff0c;1月19日&#xff0c;沪深两市收盘涨停股35只&#xff0c;其中ST股6只。群众交通、长久科技两股一字板强势涨停&#xff0c;潞安环能、跃岭股份收…

【MySQL】第五部分 多表查询

【MySQL】第五部分 多表查询 文章目录【MySQL】第五部分 多表查询5. 多表查询5.1 等值连接5.2 非等值连接5.3 自连接5.4 内连接5.5 外连接5.6 满外连接5.7 SQL99语法实现多表查询5.7.1 JOIN...ON语法5.7.2 使用SQL99语法实现内连接5.7.3 使用SQL99语法实现左外连接和右外连接5.…

postman入门

目录 新建界面 菜单区 百度翻译api实战 post 参数化 新建界面 1&#xff09;可以新建请求&#xff0c;&#xff08;rqueset&#xff09;模拟客户端的请求&#xff0c; 2&#xff09;可以创建测试集合&#xff08;collection&#xff09;&#xff0c;对接口请求进行统一管理…

删除排序链表中的重复元素

删除排序链表中的重复元素 题目描述 原始题目参考&#xff1a;删除有序链表的重复元素 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1…

java spring IOC Bean管理操作(xml P名称空间注入)

首先 我们来写一个基本的 通过xml的set属性注入 首先创建一个项目 然后引入 spring 最基本的几个依赖包 src下 下有一个 gettingStarted 包 下面有一个 user类 代码如下 package gettingStarted;public class user {public String name;public int age;public void setName(S…

leetcode 1817. 查找用户活跃分钟数【python3,哈希表的实现思路详解】

题目 给你用户在 LeetCode 的操作日志&#xff0c;和一个整数k。日志用一个二维整数数组logs表示&#xff0c;其中每个logs[i] [IDi, timei]表示ID为IDi的用户在timei分钟时执行了某个操作。 多个用户可以同时执行操作&#xff0c;单个用户可以在同一分钟内执行多个操作。指定…