HTTP 框架的设计与实现


本篇笔记以 Go 框架三件套(Web / RPC / ORM)为基础,主要介绍字节跳动的开源 Golang 微服务 HTTP 框架 Hertz。

一、 Hertz 简介

Hertz 是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 fasthttp、gin、echo 的优势, 并结合字节跳动内部的需求,使其具有高易用性、高性能、高扩展性等特点,目前在字节跳动内部已广泛使用。 如今越来越多的微服务选择使用 Golang,如果对微服务性能有要求,又希望框架能够充分满足内部的可定制化需求,Hertz 会是一个不错的选择。

架构设计:

Hertz采用了4层分层设计(应用层、路由层、协议层、传输层),保证各个层级功能内聚,同时通过层级之间的接口达到灵活扩展的目标。

1693143178323.png

框架特点:

  • 高易用性: 在开发过程中,快速写出来正确的代码往往是更重要的。因此,在 Hertz 在迭代过程中,积极听取用户意见,持续打磨框架,希望为用户提供一个更好的使用体验,帮助用户更快的写出正确的代码。
  • 高性能: Hertz 默认使用自研的高性能网络库 Netpoll,在一些特殊场景相较于 go net,Hertz 在 QPS、时延上均具有一定优势。
  • 高扩展性: Hertz 采用了分层设计,提供了较多的接口以及默认的扩展实现,用户也可以自行扩展。同时得益于框架的分层设计,框架的扩展性也会大很多。
  • 多协议支持: Hertz 框架原生提供 HTTP1.1、ALPN 协议支持。除此之外,由于分层设计,Hertz 甚至支持自定义构建协议解析逻辑,以满足协议层扩展的任意需求。
  • 网络层切换能力: Hertz 实现了 Netpoll 和 Golang 原生网络库 间按需切换能力,用户可以针对不同的场景选择合适的网络库,同时也支持以插件的方式为 Hertz 扩展网络库实现。

二、 路由

2.1 路由注册

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

方法介绍
Hertz.GET用于注册 HTTP Method 为 GET
Hertz.POST用于注册 HTTP Method 为 POST
Hertz.DELETE用于注册 HTTP Method 为 DELETE
Hertz.PUT用于注册 HTTP Method 为 PUT
Hertz.PATCH用于注册 HTTP Method 为 PATCH
Hertz.HEAD用于注册 HTTP Method 为 HEAD
Hertz.OPTIONS用于注册 HTTP Method 为 OPTIONS
Hertz.Handle支持用户手动传入 HTTP Method 用来注册方法,当用于注册普通的 HTTP Method 方法时和上述的方法作用是一致的,并且这个方法同时也支持用于注册自定义 HTTP Method
Hertz.Any用于注册所有 HTTP Method
Hertz.StaticFile/Static/StaticFS用于注册静态文件

示例代码:

package main
 
import (
	"context"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)
 
funcmain(){
	h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
 
	h.StaticFS("/", &app.FS{Root: "./", GenerateIndexPages: true})
 
	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.String(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")
	})
	h.Any("/ping_any", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "any")
	})
	h.Handle("LOAD","/load", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "load")
	})
	h.Spin()
}

2.2 路由组

Hertz 提供了路由组 ( Group ) 的能力,用于支持路由分组的功能,同时中间件也可以注册到路由组上。

示例代码:

package main
 
import (
	"context"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)
 
funcmain(){
	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()
}

2.3 路由类型

Hertz 支持丰富的路由类型用于实现复杂的功能,包括静态路由、参数路由、通配路由。

  1. 静态路由:
    路由的优先级: 静态路由 > 命名路由 > 通配路由
  2. 参数路由:
  • Hertz 支持使用 :name 这样的命名参数设置路由,并且命名参数只匹配单个路径段。
  • 如果我们设置 /user/:name 路由,匹配情况如下:
路径是否匹配
/user/gordon匹配
/user/you匹配
/user/gordon/profile不匹配
/user/不匹配
  • 通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。

示例代码:

package main
 
import (
	"context"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)
 
funcmain(){
	h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
	// This handler will match: "/hertz/version", but will not match : "/hertz/" or "/hertz"
	h.GET("/hertz/:version", func(ctx context.Context, c *app.RequestContext) {
		version := c.Param("version")
		c.String(consts.StatusOK, "Hello %s", version)
	})
	h.Spin()
}
  1. 通配路由
  • Hertz 支持使用 *path 这样的通配参数设置路由,并且通配参数会匹配所有内容。
  • 如果我们设置 /src/*path 路由,匹配情况如下:
路径是否匹配
/src/匹配
/src/somefile.go匹配
/src/subdir/somefile.go匹配
  • 通过使用 RequestContext.Param 方法,我们可以获取路由中携带的参数。

示例代码:

package main
 
import (
	"context"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)
 
funcmain(){
	h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
	// However, this one will match "/hertz/v1/" and "/hertz/v2/send"
	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)
	})
	h.Spin()
}

三、 Hertz 代码生成工具 hz

hz 是 Hertz 框架提供的一个用于生成代码的命令行工具。目前,hz 可以基于 thriftprotobuf 的 IDL 生成 Hertz 项目的脚手架。

基本使用:

  • 创建一个 Hertz 新项目
// GOPATH 下执行,go mod 名字默认为当前路径相对GOPATH的路径,也可自己指定
hz new
 
// 非GOPATH 下执行,需要指定 go mod 名
hz new -mod hertz/demo
 
// 整理 & 拉取依赖
go mod tidy
  • 编译项目
go build
  • 运行项目
./{{your binary}}
  • 测试
curl 127.0.0.1:8888/ping

如果返回 {"message":"pong"},说明接口调通。

本文主要介绍了 Golang 微服务 HTTP 框架 Hertz,只是简单的入门练习,如果想了解更多内容还是需要仔细研究官方文档 Hertz | CloudWeGo ,官方文档的内容很清晰全面,后续还需要深入学习。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简介: 本框架是在Netroid的基础之上进行了封装,节省了其中配置的过程和一些不必要的操作 主要进行文本请求和图片请求,图片请求都进行了缓存(内存缓存和sd卡缓存)的封装,sd卡缓存时间可自行更改. 文本请求可传入解析的泛型clazz,即可返回解析后的clazz对象进行数据 操作,如果不需要进行数据解析,可通过另一种方式获取原生的string; 单图请求,单图请求可执行对本地asset文件夹,sd卡,http三种请求模式.只需传入相应的路径即可; 多图请求,多图请求主要是针对listview这种图文混排模式而生,能快速加载图片并实现缓存,不需要考虑 图片错位问题.只需传入相应的url即可完成全部功能. 使用说明: 1:在新创建的Manifest.xml中application中申明: <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:name="com.aqs.application.UApplication" > 并初始化Const.init();此处的初始化主要是对内存缓存,SD卡缓存大小,缓存时间等进行设置,如果不初始化,则按使用默认配置; 2:依赖HttpAqs-library或者jar包 3:通过公有方法进行网络请求,示例如下: >文本请求: >解析后的文本请求: HttpRequest.reqquest(int,String,Parse,Class){....}; >原生string文本请求: HttpRequest.getString(String,AqsString){...} >单张图片请求: HttpRequest.setImage(ImageView,String,int,int){...} >多张图片请求: 可使用AQSImageView控件来加载图片;特别是针对listview图文混排 实现方法: >在布局中添加 >在代码中 av.setImageUrl(url);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值