深入理解Go gin框架中Context的Request和Writer对象

 更新时间:2023年04月23日 09:23:17   作者:Go学堂  
这篇文章主要为大家详细介绍了Go语言的gin框架中Context的Request和Writer对象,文中的示例代码讲解详细,对我们深入了解Go语言有一定的帮助,快跟随小编一起学习一下吧

背景

在使用gin框架时,我们定义的请求处理器,输入参数总是一个gin.Context的指针类型,代表请求的上下文。在处理器的业务逻辑中,通过Context.Request可以获取本次请求的参数值;通过Context.Writer就能将响应结果输出给客户端了。如下代码所示:

package main

import (
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
)

func main() {
	r := gin.Default()

    // 注册路由,定义请求处理器函数
	r.GET("/", func(c *gin.Context) {
        c.Param
		c.Writer.Write([]byte("Hello World"))

	})

  // 调用该函数,则禁用日志带颜色输出
	gin.DisableConsoleColor()
  
  //使用该函数,则强制日志带颜色输出,无论是在终端还是其他输出设备 
	gin.ForceConsoleColor()

	r.Run("127.0.0.1:8080")
}

那么,Context字段是在什么地方初始化的呢,为什么通过Context.Request字段就能读取请求的参数呢,又为什么通过Context.Writer字段就能将响应结果输出给客户端呢?接下来我们就一一解答这3个问题。

Context对象的初始化

gin的Context对象实际上是在Engine对象的ServeHTTP函数中进行初始化的,如下:

// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	c := engine.pool.Get().(*Context)
	c.writermem.reset(w)
	c.Request = req
	c.reset()

	engine.handleHTTPRequest(c)

	engine.pool.Put(c)
}

通过该函数我们可以看到,在第3行通过池化技术获取到一个新的Context对象。获取到该Context后,通过engine.handleHTTPRequest函数传入Context参数,进而找到对应的路由处理器,传递给具体的路由处理器。在上例中就是r.GET中的对应处理器。

在这个函数中,还会把本次的请求体req赋值给Context.Request变量。这样,在具体的请求处理器中就可以通过Context的各种方法从Request中获取参数值了。比如GetHeaderGetRawData等。

我们再来回顾下go的http的启动和请求处理流程,以便了解ServeHTTP的调用时机。engine对象实际上是实现了go的标准包中的Handler接口。该接口中定义了ServeHTTP方法。在接收到请求后,net/http的包就会调用engine的ServeHTTP方法。如下图中的engine.ServeHTTP部分:

Context.Request对象

在上节中,在Engine的ServeHTTP函数中,将函数的入参req赋值给了Context的Request对象。那么,这个req变量对象是从哪里来的呢?

Engine.ServeHTTP函数是在net/http/server.go文件的conn.serve函数中被调用的。conn代表本次请求的连接对象。conn.serve函数首先会从conn对象中读取出本次的请求参数(包含请求头等),并解析到request对象中,将该对象再赋值给Context中的Request字段。这样,通过Context的Param、Form、Header等函数,就可以从Request中读取信息了。

Context.Writer对象

在具体的请求处理函数中,我们发现所有的输出都是通过Context.Writer对象的Write函数将数据返回给客户端的。那么,这里的Context.Writer对象是什么呢,为什么通过Context.Writer就是能结果返回给客户端呢?

要回答这个问题,我们还需要回到net/http/server.go文件的conn.serve函数中,response参数是在该函数中调用ServeHTTP时传入的参数,而该response参数是通过conn.readRequest函数返回的。

我们再通过readRequest函数来看下response结构体的关键字段,如下:

我们再来看Engine.ServeHTTP函数: 首先,将response对象赋值给Context.writermem对象。即在c.writermem.reset(w)函数中执行的。 其次,Context.Writer是对Context.writermem的引用。即Context.Writer依然是指向response对象。即在c.reset()函数中执行的。

所以,在Context中跟response有关的关键字段如下:

最后,在业务逻辑中使用Context.Writer.Write函数输出时,实际上是执行的response.Write函数。

我们再来看下response.Write函数的实现:

写入的时候是调用的responsew字段写入的。那w字段又是什么呢?我们再回到server.go中的对response初始化的readRequest函数中,如下:

可以看到wresponse的对象。同时将w还赋值给了w.cw.res。最后,w.w字段是基于w.cw的一个bufio.Writer对象。当调用bufio.WriterFlush时,实际上是调用了bufio.Writer中的wrWrite方法。而wr的又是指向了chunkWriter对象的Write方法。最后该方法是执行了w.conn.bufw.Write写入了数据。

最终的写入流程如下:

总结

本文深入分析了gin框架中Context中读取请求中的数据以及写入响应数据的原理。本质上Request的数据来源于conn对象。最终也是写入到conn对象的bufw中。

以上就是深入理解Go gin框架中Context的Request和Writer对象的详细内容,更多关于Go gin框架Context的资料请关注脚本之家其它相关文章!

相关文章

  • 解决golang编译提示dial tcp 172.217.160.113:443: connectex: A connection attempt failed(推荐)

    解决golang编译提示dial tcp 172.217.160.113:443: con

    这篇文章主要介绍了解决golang编译提示dial tcp 172.217.160.113:443: connectex: A connection attempt failed,此问题完美解决,需要的朋友可以参考下
    2023-02-02
  • Go语言文件读写操作案例详解

    Go语言文件读写操作案例详解

    这篇文章主要为大家介绍了Go语言文件读写操作案例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 深入解析Golang中JSON的编码与解码

    深入解析Golang中JSON的编码与解码

    随着互联网的快速发展和数据交换的广泛应用,各种数据格式的处理成为软件开发中的关键问题,本文将介绍 Golang 中 JSON 编码与解码的相关知识,帮助大家了解其基本原理和高效应用,需要的可以收藏一下
    2023-05-05
  • Golang flag包的具体使用

    Golang flag包的具体使用

    本文主要介绍了Golang flag包的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • Goland 关闭自动移除未使用的包操作

    Goland 关闭自动移除未使用的包操作

    这篇文章主要介绍了Goland 关闭自动移除未使用的包操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go语言中并发的工作原理

    Go语言中并发的工作原理

    本文详细讲解了Go语言中并发的工作原理,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • 手把手教你导入Go语言第三方库

    手把手教你导入Go语言第三方库

    本文主要介绍了手把手教你导入Go语言第三方库,通过导入gin包来深入学习,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • GO实现跳跃表的示例详解

    GO实现跳跃表的示例详解

    跳表全称叫做跳跃表,简称跳表,是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。本文将利用GO语言编写一个跳表,需要的可以参考一下
    2022-12-12
  • Golang中的强大Web框架Fiber详解

    Golang中的强大Web框架Fiber详解

    在不断发展的Web开发领域中,选择正确的框架可以极大地影响项目的效率和成功,介绍一下Fiber,这是一款令人印象深刻的Golang(Go语言)Web框架,在本文中,我们将深入了解Fiber的世界,探讨其独特的特性,并理解为什么它在Go生态系统中引起了如此大的关注
    2023-10-10
  • 如何使用 Go 和 Excelize 构建电子表格

    如何使用 Go 和 Excelize 构建电子表格

    这篇文章主要介绍了如何使用Go和Excelize构建电子表格,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09

最新评论