前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:3 分钟说下框架中 Context 上下文的作用

面试官:3 分钟说下框架中 Context 上下文的作用

作者头像
小锟哥哥
发布2022-05-10 09:03:57
1810
发布2022-05-10 09:03:57
举报
文章被收录于专栏:GoLang全栈

在追求便利的这条路上,人们是永远不会满足的。

上一篇文章我们只实现了 web 框架中最核心的那十几行代码,但是很显然,在便利性上是不能满足的。

这边文章我们进一步再封装,创建我们的上下文。

上下文的融入

这里的上下文不是 go 标准库里面的 context ,而是我们自己去定义的上下文,但是作用和标准库里面的上下文是一样的。

那为什么不使用标准库里面的上下文呢?

先卖个关子,感兴趣可以去读下我们往期关于 标准库Context 的介绍!

什么是上下文呢?

这个的定义其实不太好去解释,你可以理解就是承接上下文的载体(变量),他可以被无限的传递下去。

举个例子:

你的朋友突然对你说:“丫的,大傻子”

你肯定以为他在骂你。

但是如果在说这句话之前,他还给你说了,一句:“我刚看到一句台词,真惊艳”

你就知道他后面那句大傻子,不是在说你了。

在程序中,也会出现这种情况,很多时候会出现方法调方法的情况,多次连调,同时下一次的调用还要使用到上次调用的结果。

此时这里就需要一个载体,来承载这些结果,并向下传递。

这就是上下文,也不知道你理解到了没?

我就当你理解了,如果没理解,可以下方给我留言。

gin 里面的上下文

首先我们先来看下上一篇文章里面,我们怎么使用 kun 框架的:

代码语言:javascript
复制
func main() {
 engine := kun.New()
 engine.GET("/", func(w http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
 })
 engine.Run(":8081")
}

再看下,gin 框架里面:

在 gin 里面,我在方法里面可以直接返回 json 等数据,同时他还能一层一层的往下传递。

再看看我们上一篇文章实现的,我们得自己去设置返回的相应头等数据,用起来就不怎么便利了。

那怎么办?

迭代呀!

开始提炼我们的上下文

创建载体

首先我们需要创建一个结构体,用来缓存数据,当做传递的载体:

代码语言:javascript
复制
type Context struct {
 Writer  http.ResponseWriter
 Req  *http.Request
 Path  string
 Method  string
 StatusCode int
}

func newContext(writer http.ResponseWriter, req *http.Request) *Context {
 return &Context{
  Writer: writer,
  Req: req,
  Path: req.URL.Path,
  Method: req.Method,
 }
}

我在里面塞入了些,我觉得接下来向下传递的过程中,有用的变量,你也可以根据你的需要进行增删。

然后在为这个载体,添加一些我们常用的方法:

代码语言:javascript
复制
// 设置消息头
func (this *Context) SetHeader(key string,value string) {
 this.Writer.Header().Set(key,value)
}
// 设置返回的code
func (this *Context) Status(code int) {
 this.StatusCode = code
 this.Writer.WriteHeader(code)
}
// 返回字符串
func (this *Context) String(code int, format string, values ...interface{})   {
 this.SetHeader("Content-Type", "text/plain")
 this.Status(code)
 this.Writer.Write([]byte(fmt.Sprintf(format, values...)))
}

我这里就写三个方法就好了,你可以根据自己需要,添加返回 json,html 等入口。

这就是我们的上下文了哈。

整合载体到框架

我们的载体创建好了,怎么整合到我们的框架里面呢?

首先,我们需要修改上一篇文章中 type HandleFun func(http.ResponseWriter, *http.Request) 的定义,改为 type HandleFun func(*ctx* Context) ,这样我们的上下文就被用上了。

其次修改 ServeHTTP 方法:

代码语言:javascript
复制
//ServeHTTP 关键方法 实现 Handler 的接口
func (this *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 key := req.Method + "-" + req.URL.Path
 if handler,ok := this.router[key];ok {
  handler(newContext(w,req))
 }else{
  fmt.Fprintf(w,"404 Not Found: %s\n", req.URL)
 }
}

当匹配到路由,调用方法时,我们传入自己定义的上下文。

最后再使用我们框架的地方,修改下回调方法:

代码语言:javascript
复制
engine := kun.New()
engine.GET("/", func(c *kun.Context) {
 c.String(200,"path: %s", c.Req.URL.Path)
})
engine.Run(":8081")

这样就可以使用到我们上下文里面的方法了。

到这来我们的上下文就封装完成了,你可以任意扩展你的上下文。

接下来我会开始搞路由部分了,目前的路由匹配方式效率是挺高的,但是并不支持 /hello/:name 这样的动态路由。

最主要他还在核心代码里面,不方便我们扩展。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GoLang全栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 上下文的融入
    • 什么是上下文呢?
      • gin 里面的上下文
      • 开始提炼我们的上下文
        • 创建载体
          • 整合载体到框架
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档