第一次链接函数

First time chaining functions

假设我想 运行 一个记录器,然后 运行 我的自定义 HTTP 服务器多路复用器。

部分方式我可以链接记录器并添加这样的自定义多路复用器:https://play.golang.org/p/Edurl-Rhqb9

package main

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

    "github.com/julienschmidt/httprouter"
)

type Middleware func(http.HandlerFunc) http.HandlerFunc

func ServeHTTPIterator(h http.HandlerFunc, m ...Middleware) http.HandlerFunc {
    if len(m) < 1 {
        return h
    }
    wrapped := h

    // loop in reverse to preserve middleware order
    for i := len(m) - 1; i >= 0; i-- {
        wrapped = m[i](wrapped)
    }
    return wrapped
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello Index!")
}

func LogFirst(h http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Print(`First`)
        h.ServeHTTP(w, r)
    })
}

func LogSecond(h http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Print(`Second`)
        h.ServeHTTP(w, r)
    })
}

func main() {
    httpServer := &http.Server{
        Addr:         `my.local:8080`,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 5 * time.Second,
        IdleTimeout:  5 * time.Second,
    }

    var Router *httprouter.Router

    preMiddle := []Middleware{
        LogFirst,
        LogSecond,
    }

    http.HandleFunc("/", ServeHTTPIterator(IndexHandler, preMiddle...))

    httpServer.Handler = Router
}

但现在假设我想 运行 我的多路复用器在记录器之后,在那种情况下我想我会做类似的事情:

    preMiddle := []Middleware{
        LogFirst,
        LogSecond,
        Router,
    }

但我不确定如何包装 Router 以使其工作,或者这是否是一种合法的方法。有人可以告诉我我在这里缺少什么吗?

修改代码以使用 http.Handler 而不是 http.HandlerFunc.

type Middleware func(http.Handler) http.Handler

func ServeHTTPIterator(h http.Handler, m ...Middleware) http.Handler {
    if len(m) < 1 {
        return h
    }
    wrapped := h

    // loop in reverse to preserve middleware order
    for i := len(m) - 1; i >= 0; i-- {
        wrapped = m[i](wrapped)
    }
    return wrapped
}
    
func LogFirst(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Print(`First`)
        h.ServeHTTP(w, r)
    })
}

func LogSecond(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Print(`Second`)
        h.ServeHTTP(w, r)
    })
}

创建路由器并向路由器注册处理程序。为 IndexHandler 添加 parameters 参数,使该函数与 httprouter 兼容。

router := httprouter.New()
router.GET("/", IndexHandler)

使用新版本的 ServeHTTPIterator 封装路由器。

httpServer.Handler = ServeHTTPIterator(router, preMiddle...)

进行这些更改后,日志将在调用路由器之前写入。

您可以实现它,而不是在您的 serveIterator 函数中传播中间件,期望像这样应用中间件片段:go playground

package main

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

    "github.com/julienschmidt/httprouter"
)

type Middleware func(http.HandlerFunc) http.HandlerFunc

func ServeHTTPIterator(h http.HandlerFunc, m []Middleware) http.HandlerFunc {
    if len(m) < 1 {
        return h
    }
    wrapped := h

    // loop in reverse to preserve middleware order
    for i := len(m) - 1; i >= 0; i-- {
        wrapped = m[i](wrapped)
    }
    return wrapped
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello Index!")
}

func LogFirst(h http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Print(`First`)
        h.ServeHTTP(w, r)
    })
}

func LogSecond(h http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Print(`Second`)
        h.ServeHTTP(w, r)
    })
}

func main() {
    httpServer := &http.Server{
        Addr:         `my.local:8080`,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 5 * time.Second,
        IdleTimeout:  5 * time.Second,
    }

    var Router *httprouter.Router
    
    preMiddle := []Middleware{
        LogFirst,
        LogSecond,
    }

    http.HandleFunc("/", ServeHTTPIterator(IndexHandler, preMiddle))

    httpServer.Handler = Router
}