【问题标题】:Gorilla mux custom middlewareGorilla mux 自定义中间件
【发布时间】:2014-11-30 00:28:01
【问题描述】:

我正在使用 gorilla mux 来管理路由。我缺少的是在每个请求之间集成一个中间件。

例如

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "log"
    "net/http"
    "strconv"
)

func HomeHandler(response http.ResponseWriter, request *http.Request) {

    fmt.Fprintf(response, "Hello home")
}

func main() {

    port := 3000
    portstring := strconv.Itoa(port)

    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    http.Handle("/", r)

    log.Print("Listening on port " + portstring + " ... ")
    err := http.ListenAndServe(":"+portstring, nil)
    if err != nil {
        log.Fatal("ListenAndServe error: ", err)
    }
}

每个传入的请求都应该通过中间件。如何在此处集成中间件?

更新

我会将它与 gorilla/sessions 结合使用,他们说:

重要提示:如果您不使用 gorilla/mux,则需要将您的 处理程序与 context.ClearHandler as 否则你会泄漏内存!一个 简单的方法是在调用时包装顶层多路复用器 http.ListenAndServe:

如何防止这种情况发生?

【问题讨论】:

标签: go gorilla


【解决方案1】:
func Middleware(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // do stuff
        h.ServeHTTP(w, r)
    })
}
func Middleware2(s string) mux.MiddlewareFunc {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // do stuff
            fmt.Println(s)
            h.ServeHTTP(w, r)
        })
    }
}
func main() {
    router := mux.NewRouter()


    router.Use(Middleware)
    //you can apply it to a sub-router too
    subRouter := router.PathPrefix("/sub_router/").Subrouter()
    subRouter.Use(Middleware2("somePrams"))
    // Add more middleware if you need call router.Use Again
    // router.Use(Middleware3, Middleware4, Middleware5)

    _ = http.ListenAndServe(":80", router)
}

the official doc on the mux website

【讨论】:

    【解决方案2】:

    如果您想将中间件链应用于路由器或子路由器的所有路由,您可以使用 Gorilla mux 的 fork https://github.com/bezrukovspb/mux

    subRouter := router.PathPrefix("/use-a-b").Subrouter().Use(middlewareA, middlewareB)
    subRouter.Path("/hello").HandlerFunc(requestHandlerFunc)
    

    【讨论】:

    • 谢谢老兄!这种 express.js 中间件风格正是我想要的
    • gorilla mux 中内置了中间件使用
    • @ozy 你的意思是router.Use(),不过最好用一个子路由器,这样中间件可以应用到不同的地方。
    【解决方案3】:

    我不确定为什么@OneOfOne 选择将路由器链接到中间件,我认为这是更好的方法:

    func main() {
        r.Handle("/",Middleware(http.HandlerFunc(homeHandler)))
        http.Handle("/", r)
    }
    
    func Middleware(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        h.ServeHTTP(w, r)
    })}
    

    【讨论】:

    • 这种方法正是我想要的——带有中间件的嵌套Handle。谢谢!
    • 这和@OneOfOne 的回答差不多
    【解决方案4】:

    只需创建一个包装器,在 Go 中相当容易:

    func HomeHandler(response http.ResponseWriter, request *http.Request) {
    
        fmt.Fprintf(response, "Hello home")
    }
    
    func Middleware(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Println("middleware", r.URL)
            h.ServeHTTP(w, r)
        })
    }
    func main() {
        r := mux.NewRouter()
        r.HandleFunc("/", HomeHandler)
        http.Handle("/", Middleware(r))
    }
    

    【讨论】:

    • 谢谢你,h.ServeHTTP(w, r) 这部分是我所缺少的。他们并没有说得很清楚如何直接调用 Handler。
    • 也可以使用r.Use(Middleware)注册中间件。
    【解决方案5】:

    您可以考虑使用中间件包,例如 negroni

    【讨论】:

    • 当我使用gorilla/sessions时,它不会发生内存泄漏?
    • 我无法编辑,因为Suggested edit queue is full链接 不再存在。我想换一个新的negroni