day 5|中间件

时间:2024-03-29 13:27:12

本节目标:

  • 设计并实现 Web 框架的中间件(Middlewares)机制。

  • 实现通用的Logger中间件,能够记录请求到响应所花费的时间,代码约50行

中间件是啥

我们的框架不可能理解所有的业务,框架只是一个空空的躯体,他有什么具体的功能,需要我们去实现

这个时候,中间件就出来了,类似于一个插件,嵌入到框架中

对中间件需要考虑两个点:

  • 插入点在哪里,不能太底层了,那样逻辑会非常复杂

  • 中间件的参数决定了扩展能力

中间件设计

我们对Context对象进行设计,目的是框架接收初始化Context对象后,允许用户使用自己定义的中间件做一些额外的请求。

package gee

import (
    "log"
    "time"
)

func Logger() HandlerFunc {
    return func(c *Context) {
        //start time
        t := time.Now()
        //process request  等待用户自己定义的Handler处理结束
        c.Next()
        //caculate resolution time
        log.Printf("[%d] %s in %v", c.StatusCode, c.Req.RequestURI, time.Since(t))
    }
}

注意我们支持设置多个中间件,一次进行调用

但是中间件应该复制在GROUP最顶层,这说明中间件需要有足够的功能通用性

中间件可以处理流程前,也可以处理流程后,而且中间件可能不止一个,所以我们要设计一个数组类型的HandlerFunc

type Context struct {
    // origin objects
    Writer http.ResponseWriter
    Req    *http.Request
    // request info
    Path   string
    Method string
    Params map[string]string
    // response info
    StatusCode int
    // middleware
    handlers []HandlerFunc//存储中间件
    index    int  //记录第几个中间件
}

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

func (c *Context) Next() {
    c.index++  //
    s := len(c.handlers)
    for ; c.index < s; c.index++ {
        c.handlers[c.index](c)
    }
}

在这一章里面,大家还是要去看一下源码,感觉文章里面有些东西没写清楚,特别是测试的main部分

这里测试的话不要使用curl工具,直接在网页上面访问url,服务端口才会有访问的时间