如何对所有请求使用大猩猩中间件处理程序?

Luc*_*cas 4 router go mux

我想使用此处指定的处理程序来记录所有内容。

这就是我所拥有的:

r := mux.NewRouter()
s := r.PathPrefix("/api/v1").Subrouter()

s.HandleFunc("/abc", handler.GetAbc).Methods("GET")
s.HandleFunc("/xyz", handler.GetXyz).Methods("GET")
Run Code Online (Sandbox Code Playgroud)

我想使用日志中间件,但我不想在每一行中重复它,正如它们在 github 中显示的那样:

r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
r.HandleFunc("/", ShowIndex)
Run Code Online (Sandbox Code Playgroud)

有没有办法只将通用日志中间件传递给r,所有通过r路由器的东西都会先通过中间件?

Bur*_*dar 5

使用中间件:

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Do stuff here
        log.Println(r.RequestURI)
        // Call the next handler, which can be another middleware in the chain, or the final handler.
        next.ServeHTTP(w, r)
    })
}


r.Use(loggingMiddleware)

Run Code Online (Sandbox Code Playgroud)

这是文档:https : //github.com/gorilla/mux#middleware

  • 我想使用 gorilla 的 LoggingHandler。我把它包装在中间件中 (2认同)

Luc*_*cas 5

我用中间件函数包装了 LoggingHandler

func loggingMiddleware(next http.Handler) http.Handler {
    return handlers.LoggingHandler(os.Stdout, next)
}

r.Use(loggingMiddleware)
Run Code Online (Sandbox Code Playgroud)


Pra*_*tne 5

这是我采取的方法,这对我来说效果最好。


type Route struct {
    Name        string
    Method      string
    Pattern     string
    Secure      bool
    HandlerFunc http.HandlerFunc
}

type Routes []Route

var routes = Routes{
    Route{
        Name:        "Docs",
        Method:      "GET",
        Pattern:     "/v2/docs",
        HandlerFunc: Docs,
    },

    Route{
        Name:        "GetUserByName",
        Method:      "GET",
        Pattern:     "/v2/user/{username}",
        HandlerFunc: user.GetUserByName,
        Secure:      true,
    },
}

func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    router.NotFoundHandler = http.HandlerFunc(notFound)
    router.MethodNotAllowedHandler = http.HandlerFunc(notAllowed)
    for _, route := range routes {
        var handler http.Handler
        if route.Secure {
            handler = AuthMiddleware(route.HandlerFunc)
        } else {
            handler = route.HandlerFunc
        }

        handler = Logger(os.Stderr, handler)

        router.
            Methods(route.Method).
            Path(route.Pattern).
            Name(route.Name).
            Handler(handler)
    }

    return router
}

func ApplicationRecovery(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                fmt.Fprintln(os.Stderr, "Recovered from application error occurred")
                _, _ = fmt.Fprintln(os.Stderr, err)
                w.WriteHeader(http.StatusInternalServerError)
                }))
            }
        }()
        next.ServeHTTP(w, r)
    })
}

func Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Add("Content-Type", "application/json")
        next.ServeHTTP(w, r)
    })
}

func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //TODO: Add authentication
        log.Println("Authentication required")
        next.ServeHTTP(w, r)
    })
}

func Logger(inner http.Handler, name string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()

        log.Printf(
            "%s %s %s %s",
            r.Method,
            r.RequestURI,
            name,
            time.Since(start),
        )

        inner.ServeHTTP(w, r)
    })
}

func notFound(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusNotFound)
}

func notAllowed(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusMethodNotAllowed)
}

func main() {
    srv := http.Server{
        Addr:         "0.0.0.0:8080",
        Handler:      ApplicationRecovery(Middleware(NewRouter())),
        ReadTimeout:  15 * time.Second,
        WriteTimeout: 15 * time.Second,
    }

    log.Fatal(srv.ListenAndServe())
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以覆盖我的基础:

  • 请求执行期间出现恐慌
  • 一个通用中间件,为所有请求设置响应标头
  • 用于所有请求日志记录的日志记录中间件
  • 安全资源的身份验证中间件

正在运行的处理程序的控制台日志

2020/06/23 22:28:48 Server started
2020/06/23 22:28:51 Authentication required
2020/06/23 22:28:51 Begin x-api-key validation
2020/06/23 22:28:51 x-api-key matched user: 1
2020/06/23 22:28:51 User 1 successfully accessed secure resourecs
::1 - - [23/Jun/2020:22:28:51 +0100] "DELETE /v2/user/john?permanent=true HTTP/1.1" 403 85
Run Code Online (Sandbox Code Playgroud)