美文网首页golang 编程笔记
【golang】 http的中间件

【golang】 http的中间件

作者: dongzd | 来源:发表于2020-03-12 19:34 被阅读0次

    中间件Middleware

    所谓中间件,就是连接上下级不同功能的函数或者软件,通常进行一些包裹函数的行为,为被包裹函数提供添加一些功能或行为。前文的HandleFunc就能把签名为 func(w http.ResponseWriter, r *http.Reqeust)的函数包裹成handler。这个函数也算是中间件。

    这里我们以HTTP请求的中间件为例子,提供一个log中间件,能够打印出每一个请求的log。

    go的http中间件很简单,只要实现一个函数签名为func(http.Handler) http.Handler的函数即可。http.Handler是一个接口,接口方法我们熟悉的为serveHTTP。返回也是一个handler。因为go中的函数也可以当成变量传递或者或者返回,因此也可以在中间件函数中传递定义好的函数,只要这个函数是一个handler即可,即实现或者被handlerFunc包裹成为handler处理器。

    func middlewareHandler(next http.Handler) http.Handler{
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
            // 执行handler之前的逻辑
            next.ServeHTTP(w, r)
            // 执行完毕handler后的逻辑
        })
    }
    

    这种方式在Elixir的Plug框架中很流行,思想偏向于函数式范式。熟悉python的朋友一定也想到了装饰器。闲话少说,来看看go是如何实现的吧:

    func loggingHandler(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            log.Printf("Started %s %s", r.Method, r.URL.Path)
            next.ServeHTTP(w, r)
            log.Printf("Comleted %s in %v", r.URL.Path, time.Since(start))
        })
    }
    
    func main() {
        http.Handle("/", loggingHandler(http.HandlerFunc(index)))
        http.ListenAndServe(":8000", nil)
    }
    

    loggingHandler即是一个中间件函数,将请求的和完成的时间处理。可以看见请求或go的输出:

    2016/12/04 21:18:13 Started GET /
    2016/12/04 21:18:13 Comleted / in 13.365µs
    2016/12/04 21:18:20 Started GET /
    2016/12/04 21:18:20 Comleted / in 17.541µs
    

    既然中间件是一种函数,并且签名都是一样,那么很容易就联想到函数一层包一层的中间件。再添加一个函数,然后修改main函数:

    func hook(next http.Handler) http.Handler{
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Println("before hook")
            next.ServeHTTP(w, r)
            log.Println("after hook")
    
        })
    }
    
    func main() {
        http.Handle("/", hook(loggingHandler(http.HandlerFunc(index))))
        http.ListenAndServe(":8000", nil)
    }
    

    在loggingHandler再包了一层hook,可以看到输出为:

    2016/12/04 21:26:30 before hook
    2016/12/04 21:26:30 Started GET /
    2016/12/04 21:26:30 Comleted / in 14.016µs
    2016/12/04 21:26:30 after hook
    

    函数调用形成了一条链,可以是在这条链上做很多事情。当然go的写法上,比起elixir的|>的符号,优雅性略差。

    相关文章

      网友评论

        本文标题:【golang】 http的中间件

        本文链接:https://www.haomeiwen.com/subject/qliijhtx.html