Go语言学习 - RPC篇:gin框架的基础能力剖析

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: gin是非常流行的一款HTTP框架。相较于原生的HTTP server,gin有很多改进点,主要在于3点:1. 上手简单,开发思路与原生HTTP基本一致2. 引入多个工具库,提高了开发效率3. 生态丰富,有许多开源的组件围绕着gin框架,我们将展开今天的话题。

gin框架

gin是非常流行的一款HTTP框架。相较于原生的HTTP server,gin有很多改进点,主要在于3点:

  1. 上手简单,开发思路与原生HTTP基本一致
  2. 引入多个工具库,提高了开发效率
  3. 生态丰富,有许多开源的组件

围绕着gin框架,我们将展开今天的话题。

// 请求结构体
type MyRequest struct {
    MyInfo string `form:"my_info" json:"my_info"`
}

// 响应结构体
type MyResponse struct {
    Errno  int    `json:"errno"`
    Result string `json:"result"`
    MyInfo string `form:"my_info" json:"my_info"`
}

// handler
func GetData(c *gin.Context) {
    var b MyRequest
    err := c.Bind(&b)
    if err != nil {
        c.JSON(http.StatusOK, MyResponse{
            Errno: 1,
        })
        return
    }

    c.JSON(http.StatusOK, MyResponse{
        Result: "my result",
    })
}

func main() {
    // gin server
    r := gin.Default()
    // 中间件
    r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
        if err, ok := recovered.(string); ok {
            c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
        }
        c.AbortWithStatus(http.StatusInternalServerError)
    }))

    r.GET("/data", GetData)
    r.Run()
}

关键函数分析

路由注册

func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes 

func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes

Gin支持不同HTTP方法的路由注册,这对RESTful风格的代码编写带来了很大帮助。对于阅读代码的同学,可以快速地通过路由注册的列表,如r.GET("/data", GetData),找到对应的方法。

Handler函数

type HandlerFunc func(*Context)

Handler函数相较于标准库,看似从2个参数RequestResponseWriter 转变成了一个参数 Context,简化了调用,但其实对调用者来说,复杂度并没有降低:

  1. Context 包含大量数据结构
  2. Context 包含了大量的方法

对于一名新手,在摸索出一条最佳实践路径前,学习成本不增反减。这主要是因为gin.Context过重。从编程角度来看,这个对象包含了过多信息,是个大而杂的工具集。

但不可否认的是,gin里提供了很多工具都比原生库好用,例如参数绑定、返回JSON数据。

绑定参数Bind

func (c *Context) Bind(obj any) error

Bind中引入了泛型中的any特性,但使用和原先的interface{}完全一致:

调用方可以填任意值。但实际上,Bind中必须为一个指针类型的数据结构,但由于interface{}对入参没有任何编译时的限制,导致传参问题在运行时才会报错。

例如:

var b MyRequest
// 正确
c.Bind(&b)
// 错误:编译正确,但运行时异常
c.Bind(b)
c.Bind(1)

返回JSON数据

func (c *Context) JSON(code int, obj any)

该方法是返回HTTP状态码为code,并且将obj数据进行JSON序列化。

它的问题同Bind函数,这里就不再赘述了。

middleware

gin框架提供了middleware的能力,它可以为整个Server提供一个公共能力的封装。有了middleware,整个server处理请求变成了:

middleware预处理 -> handler -> middleware后处理

  • 常见的预处理如

    • 参数校验
    • 用户认证
    • panic恢复
  • 常见的后处理则如

    • 定制HTTP状态码
    • 异常数据封装

总体来说,middleware能帮助用户减少重复性代码的编写,沉淀为公共能力,堪称web编程的一大利器。

gin能力剖析

我们先看看gin的改进点:

  1. mux支持RESTful风格的接口定义
  2. gin.Context提供了大量的工具,简化解析、返回的相关代码
  3. middleware可解决大量重复性的代码

这三点对开发者带来了不小的帮助。但是,我们在使用gin作为开发工具时,仍有一些问题:

  1. 大量的参数类型都是interface{}类型的数据结构,需要调用方自行保证
  2. gin.Context过大,学习和理解的成本很高
  3. 不少问题要在运行时才能发现,编译期无能为力

这些弊端汇总起来,依旧是和handler的函数定义相关:没有充分地利用Go强类型、编译检查的特点,来提高程序的质量、降低开发者的学习成本

更简单的Handler框架

那么,什么样的Handler框架对用户来说效果更好呢?我这边给出一个函数签名:

 func BetterHandler(ctx context.Context, req *MyRequest) (rsp *MyResponse, err error)

我们依次看一下这些参数及其使用场景:

  1. ctx - 上下文,传递公共参数以及超时控制
  2. req - 请求的参数结构
  3. rsp - 响应的参数结构
  4. err - 错误信息

从整个RPC框架来看,它重点做了2件事:

  1. 自动将http参数解析到ctx和req中

    1. 解析规则按标准约定,如HTTP RESTful
    2. 一般是将Header里的信息放到ctx中,将URL+Body里的信息匹配到req结构体
  2. 自动将rsp和err对应到HTTP响应中

    1. err=nil时,认为请求成功,将rsp序列化后、填入到HTTP Body中
    2. err!=nil时,认为请求去失败,返回约定的协议(如异常状态码、异常HTTP的Body)

BetterHandler是一个很棒的编程体验:

  1. 无需关心解析参数与返回响应这两步的具体实现,统一由框架封装
  2. 函数的输入和输出都是强类型的,开发者有了一个明确的“模板”
  3. 将handler中的业务逻辑与RPC框架中协议部分解耦

也许你一下子无法快速理解,但反复对比下,你会逐渐体会到其中的精妙。但是,使用这个框架前,我们要解决以下两个问题:

  1. URL与Handler的匹配逻辑
  2. 怎么约定解析请求和返回响应的协议

小结

今天,我们一起看了gin框架的相关示例,编程体验比原生http库有了明显提升。gin的生态也给出了不少的优化方案或者插件,但由于框架本身限制,很难治本。

下一讲,我们将来看一个我最为推荐的RPC框架,分析一下其相关利弊。

目录
相关文章
|
6月前
|
缓存 NoSQL Go
通过 SingleFlight 模式学习 Go 并发编程
通过 SingleFlight 模式学习 Go 并发编程
|
2月前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。
|
3月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
229 4
|
3月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
221 1
|
3月前
|
数据采集 监控 Java
go语言编程学习
【11月更文挑战第3天】
57 7
|
3月前
|
自然语言处理 负载均衡 API
gRPC 一种现代、开源、高性能的远程过程调用 (RPC) 可以在任何地方运行的框架
gRPC 是一种现代开源高性能远程过程调用(RPC)框架,支持多种编程语言,可在任何环境中运行。它通过高效的连接方式,支持负载平衡、跟踪、健康检查和身份验证,适用于微服务架构、移动设备和浏览器客户端连接后端服务等场景。gRPC 使用 Protocol Buffers 作为接口定义语言,支持四种服务方法:一元 RPC、服务器流式处理、客户端流式处理和双向流式处理。
|
3月前
|
设计模式 测试技术 Go
学习Go语言
【10月更文挑战第25天】学习Go语言
40 4
|
5月前
|
JSON Go API
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
|
5月前
|
编译器 Go
go语言学习记录(关于一些奇怪的疑问)有别于其他编程语言
本文探讨了Go语言中的常量概念,特别是特殊常量iota的使用方法及其自动递增特性。同时,文中还提到了在声明常量时,后续常量可沿用前一个值的特点,以及在遍历map时可能遇到的非顺序打印问题。
|
6月前
|
Dubbo 网络协议 Java
RPC框架:一文带你搞懂RPC
这篇文章全面介绍了RPC(远程过程调用)的概念、原理和应用场景,解释了RPC如何工作以及为什么在分布式系统中广泛使用,并探讨了几种常用的RPC框架如Thrift、gRPC、Dubbo和Spring Cloud,同时详细阐述了RPC调用流程和实现透明化远程服务调用的关键技术,包括动态代理和消息的编码解码过程。
RPC框架:一文带你搞懂RPC