golang 中间件

golang 中间件如js闭包,亦似python中装饰器。本质走的还是偏函数,柯里化,只不过执行改造成管道式。

Basic

http几个相关的概念

  • http.Handler 只有一个ServeHTTP操作的接口
  • http.HandlerFunc 适配普通函数为 HTTP handlers
  • http.Handle 允许用正则字符串在 DefaultServeMux 上注册 http.Handler

示例 日志中间件 将 http.HandlerFunc作为入参,作了包装并返回新的http.HandlerFunc类型供服务端调用。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func logging(f http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        log.Println(r.URL.Path)
        f(w, r)
    }
}

func foo(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "foo")
}

func bar(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "bar")
}

func main() {
    http.HandleFunc("/foo", logging(foo))
    http.HandleFunc("/bar", logging(bar))

    http.ListenAndServe(":8080", nil)
}

测试

用命令行工具httpie

$ go run basic-middleware.go
2017/02/10 23:59:34 /foo
2017/02/10 23:59:35 /bar
2017/02/10 23:59:36 /foo?bar

$ http :8080/foo
$ http :8080/bar
$ http :8080/foo?bar

Advance

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

// 定义中间件类型
type Middleware func(http.HandlerFunc) http.HandlerFunc

func Logging() Middleware {
    // 创建中间件
    return func(f http.HandlerFunc) http.HandlerFunc {
        // 定义 http.HandlerFunc
        return func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            defer func() {
                log.Println(r.URL.Path, time.Since(start))
            }()

            // 在链中调用下一个中间件或handler
            f(w, r)
        }
    }
}

// 谓词中间件,确保请求方式是指定的http谓词动作
func Method(m string) Middleware {
    return func(f http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            if r.Method != m {
                http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
                return
            }

            f(w, r)
        }
    }
}

// 调用链串应用多个中间件产生一个 http.HandlerFunc
// 类似pipe 管道, 上游的输出视为下游的输入
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
    for _, m := range middlewares {
        f = m(f)
    }
    return f
}

func Hi(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hi, pardon110")
}

func main() {
    http.HandleFunc("/", Chain(Hi, Method("GET"), Logging()))
    http.ListenAndServe(":8080", nil)
}

测试

发起请求

C:\Users\Administrator>http post :8080/hi
HTTP/1.1 400 Bad Request
Content-Length: 12
Content-Type: text/plain; charset=utf-8
Date: Fri, 19 Mar 2021 11:17:13 GMT
X-Content-Type-Options: nosniff

Bad Request


C:\Users\Administrator>http :8080/hi
HTTP/1.1 200 OK
Content-Length: 14
Content-Type: text/plain; charset=utf-8
Date: Fri, 19 Mar 2021 11:17:33 GMT

Hi, pardon110

服务端响应

D:\code-base\gomod\tt\web>go run "d:\code-base\gomod\tt\web\middleware\advance\advancet.go"
2021/03/19 19:17:13 /hi 0s
2021/03/19 19:17:33 /hi 0s
本作品采用《CC 协议》,转载必须注明作者和本文链接
pardon110
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
开发者 @ 社科大
文章
133
粉丝
24
喜欢
100
收藏
54
排名:107
访问:8.9 万
私信
所有博文
社区赞助商