gin 之 Context

gin 之 Context

Context 是 gin 当中最为重要的一部分,它用于在中间件当中传递变量,管理流程,请求和响应部分 都封装在 Context,Context 是 gin 中上下文管理的核心,它包括了请求处理,响应处理,表单解析等重要工作。

Go 标准库 Context 和 gin Context

从go1.7开始,golang.org/x/net/context包正式作为context包进入了标准库。那么,这个包到底是做什么的呢?根据官方的文档说明:

Package context defines the Context type, which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes.

也就是说,通过context,我们可以方便地对同一个请求所产生地goroutine进行约束管理,可以设定超时、deadline,甚至是取消这个请求相关的所有goroutine。使用context可以使开发者方便的在这些goroutine里传递request相关的数据、取消goroutine的signal或截止日期。也就是说引入Context主要是为了方便管理gotoutine从而更容易的实现并发编程。来看看它的接口设计:

type Context interface {
    //Done 当绑定当前context的任务被取消时,将返回一个关闭的channel;如果当前context不会被取消,将返回nil
    Done() <-chan struct{}

    //如果Done返回的channel没有关闭,将返回nil;如果Done返回的channel已经关闭,将返回非空的值表示任务结束的原因。如果是context被取消,Err将返回Canceled;如果是context超时,Err将返回DeadlineExceeded
    Err() error

    // Deadline返回绑定当前context的任务被取消的截止时间
    Deadline() (deadline time.Time, ok bool)

    // Value 返回context存储的键值对中当前key对应的值,如果没有对应的key,则返回nil
    Value(key interface{}) interface{}
}

上面就是Context interface ,可以看出它的设计主要就是用于控制管理goroutine 的生命周期的,但gin Context 主要是请求处理响应处理表单解析上下文管理等重要工作,当然它也实现了这个interface 的四个方法,只不过除了Value 方法之外其它的几个方法都是空实现,如果想实现其它几个方法,应该使用gin Request.Context() ,具体见gin context 源码gin Context 内部封装了大量的细节,接下来看看。

数据结构

  • Context

    type Context struct {
        writermem responseWriter // 实现了 golang net/http ResponseWriter 接口
        Request   *http.Request  // golang net/http Request 对象
    
        Params   Params // 数组,按序记录了URL 参数
        handlers HandlersChain // 中间件数组
        index    int8  // 记录当前执行到的中间件index,初始化被置为-1
        fullPath string // URL 路径
    
        engine *Engine // gin engine
    
        mu sync.RWMutex // 锁,防止keys map 被并发修改
    
        // Keys is a key/value pair exclusively for the context of each request.
        Keys map[string]interface{} // Keys 用来存储每次request的键值对
    
      ...
    }

    Context 是 gin 中最为重要的部分,它的主要功能是传递变量,管理流程,接收验证request以及渲染响应response,其中的writermemRequest 字段实现了Gonet/httpResponseWriterRequest接口,因此具备了读取请求和响应请求的能力,其中的paramsfullPath则是分别记录请求的URL参数和完整的URL路径,handlersindex则是为中间件服务的,handlers按照定义顺序记录了所有注册的中间件函数,而index则记录当前执行到的中间件index,初始化被设置为-1。Keys则是被用来传递流程中的变量。

  • Engine

type Engine struct {
  RouterGroup 
  ... // 省略一些次要字段
}

// RouterGroup (路由组)被用来在内部配置路由,一个RouterGroup 和URL 前缀以及一组中间件关联(中间件也叫middleware,后面会详细介绍gin的middleware,这里只要知道middleware本质上也是一些处理函数即可)
type RouterGroup struct {
    Handlers HandlersChain // handerFunc 数组(一组中间件)
    basePath string // 路由组URL前缀
    engine   *Engine
    root     bool // 是否根节点(这里涉及到路由树,在讲解路由的时候再讲)
}

Engine 是一个框架的实例,它包含了路由、中间件、配置选项,New() 或者 Default() 创建一个EngineRouterGroup提供路由分组的能力,被用来在内部配置路由,一个RouterGroup 和URL 前缀以及一组中间件关联(中间件也叫middleware,后面会详细介绍gin的middleware,这里只要知道middleware本质上也是一些处理函数即可),由此可知gin的中间件不仅可以全局可用,还可以运用在不同的路由组。

Context 提供的方法

  • 中间件相关

    // 下一个中间件
    func (c *Context) Next() {
        c.index++ // 当前执行到的中间件index + 1
        for c.index < int8(len(c.handlers)) { // 依次执行后面所有的中间件
            c.handlers[c.index](c)
            c.index++
        }
    }
    // 终止后面的中间件(handerFunc)处理(gin 也提供了AbortWithStatus、AbortWithStatusJSON等方法)
    func (c *Context) Abort() {
        c.index = abortIndex // abortIndex 是常量changmath.MaxInt8/2,直接将context.index 置为无穷大,后面的中间件han

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

go高薪必备:面试框架17讲 文章被收录于专栏

<p> <span style="font-size:14px;">本专刊是Go开源项目源码分析专栏,共 17 篇文章,挑选了Go 开源界知名的 4 个开源项目gnet(高效的网络库)、gin(知名的Go微型web框架)、fasthttp(高性能web框架)、nsq(Go消息队列)来对它们进行源码分析,分析它们的设计思想和代码实现。每个项目的讲解都是由浅入深,由设计思想的剖析到源码实现的分析,更易于读者理解。</span> </p> <p> <br /> </p> <h2> <b><span style="font-size:16px;line-height:1;">购买须知:</span></b> </h2> <span style="font-size:14px;">订阅成功后,用户即可通过牛客网 PC 端、App 端享有永久阅读的权限;</span><br /> <span style="font-size:14px;">牛客专刊为虚拟内容服务,订阅成功后概不退款;</span><br /> <span style="font-size:14px;line-height:1;">在专刊阅</span><span style="font-size:14px;line-height:1;">读过程中,如有任何问题,可在文章评论区底部留言,或添加牛客导师,加入读者交流群;</span><br /> <span style="font-size:14px;">想成为牛客作者,请邮件联系yinxiaoxiao@nowcoder.com,邮件主题【牛客作者+写作方向】,并附上个人简历一份及近期作品一份;</span><br /> <p> <span style="font-size:14px;">牛客专刊版权归本平台所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布 / 发表,违者将依法追究责任</span><span style="font-size:14px;">。</span> </p> <p> <br /> </p>

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务