转到httprouter自定义中间件

时间:2019-12-10 22:02:10

标签: go

作为一名Go程序员,我相对较新,并且正在尝试为服务器构建自定义的中间件。问题在于它的行为不像我预期的那样。有人可以解释为什么我的上下文未设置为 ME 吗?

package main

import (
    "context"
    "log"
    "net/http"

    "github.com/julienschmidt/httprouter"
)

func main() {
    router := httprouter.New()
    router.GET("/test", middlewareChain(contentType, name))
    log.Print("App running on 8080")
    log.Fatal(http.ListenAndServe(":8080", router))
}

func middlewareChain(h ...httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
        r = r.WithContext(context.WithValue(r.Context(), "test", "You"))
        log.Print("Set context to YOU")
        for _, handler := range h {
            handler(w, r, p)
        }
    }
}

func contentType(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
    r = r.WithContext(context.WithValue(r.Context(), "test", "Me"))
    log.Print("Set context to ME")
    header := w.Header()
    header.Set("Content-type", "application/json")
}

func name(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
    log.Printf("Context: %s", r.Context().Value("test"))
}

https://imgur.com/4ILu7fk Result

1 个答案:

答案 0 :(得分:1)

我发现如果中间件链接到下一个中​​间件,那么中间件最有用。堆栈中后面的中间件可以依赖于先前的中间件设置的值,因此它们是顺序相关的。有时,他们可以决定在某种情况下停止堆栈。

如何像这样将它们链接起来?

func main() {
    router := httprouter.New()
    router.GET("/test", setTestYou(contentType(name)))
    log.Print("App running on 8080")
    log.Fatal(http.ListenAndServe(":8080", router))
}

func setTestYou(next httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
        r = r.WithContext(context.WithValue(r.Context(), "test", "You"))
        log.Print("Set context to YOU")

        if next != nil {
            next(w, r, p)
        }
    }
}

func contentType(next httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
        if r.Header.Get("Content-type") != "application/json" {
            // break here instead of continuing the chain
            w.Status = 400
            return
        }

        r = r.WithContext(context.WithValue(r.Context(), "test", "Me"))
        log.Print("Set context to ME")
        header := w.Header()
        header.Set("Content-type", "application/json")

        if next != nil {
            next(w, r, p)
        }
    }
}

func name(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
    log.Printf("Context: %s", r.Context().Value("test"))
}

由于他们将请求/上下文传递到下一个请求,因此更改将保留。