跟Gin一块搭建自己的web框架(五)
继续扩展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