继续扩展web框架的功能。

context作为某个请求的上下文,必然就需要承担它最基本的功能:在各个中间件和函数之间传递变量。所以我们在context的结构体定义中加入一个Keys的字段,用来放置上下文的变量。

// Context .
	Context struct {
		Req      *http.Request
		Writer   http.ResponseWriter
		Keys     map[string]interface{}
		Params   httprouter.Params
		handlers []HandlerFunc
		engine   *Engine
		index    int8
	}

然后我们需要一个Set函数用来将中间的变量设置进context中

// Set Sets a new pair key/value just for the specefied context.
// It also lazy initializes the hashmap
func (c *Context) Set(key string, item interface{}) {
	if c.Keys == nil {
		c.Keys = make(map[string]interface{})
	}
	c.Keys[key] = item
}

设置的时候需要判断Keys是否初始化了, 如果没有初始化的话,需要先出示话,这个如果对于单例模式有了解的话,就很好理解,相当于懒汉模式。

设置了变量,在需要读取的时候,通过Get函数从context里边取出对应的变量。

// Get Returns the value for the given key.
// It panics if the value doesn't exist.
func (c *Context) Get(key string) interface{} {
	var ok bool
	var item interface{}
	if c.Keys != nil {
		item, ok = c.Keys[key]
	} else {
		item, ok = nil, false
	}
	if !ok || item == nil {
		log.Panicf("Key %s doesn't exist", key)
	}
	return item
}

那么怎么使用context来传递变量呢,还是用上一篇的例子。

我们修改一下,在定义路由的时候,采用路由变量的方式传递一个name变量进去

v1 := r.Group("/v1")
	{
		v1.GET("/login/:name", v1IndexLoginfunc)
	}

在对应的handler中,从Params中取出name变量,然后将这个变量写入到context

func v1IndexLoginfunc(c *gin.Context) {
	name := c.Params.ByName("name")
	c.Set("innerName", name)
	message := getInfo(c)
	c.String(200, message)
}

假设getInfo函数能够通过name获取对应的用户信息,例子中只是简单的返回了一个字符串。

func getInfo(c *gin.Context) string {
	name := c.Get("innerName")
	message := "welcome " + name.(string) // 前提是知道这个是string类型
	return message
}

将web框架启动之后,访问http://localhost:8080/v1/login/harleylau, 会在浏览器显示 “welcome harleylau” ,说明name变量成功的通过context传递到了getInfo函数中。

此外,为了能够在发生错误的时候,主动的中断请求, 在context中新增了几个函数用来主动的退出。

// Abort .
func (c *Context) Abort(code int) {
	c.Writer.WriteHeader(code)
	c.index = AbortIndex
}

// Fail .
func (c *Context) Fail(code int, err error) {
	c.Error(err, "Operation aborted")
	c.Abort(code)
}

func (c *Context) Error(err error, meta interface{}) {
	c.Errors = append(c.Errors, ErrorMsg{
		Message: err.Error(),
		Meta:    meta,
	})
}

对应的代码地址: https://github.com/harleylau/myGin/tree/master/v0.3