【问题标题】:How to use gorilla middleware handlers for all requests?如何对所有请求使用 gorilla 中间件处理程序?
【发布时间】:2020-10-13 23:53:03
【问题描述】:

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

这就是我所拥有的:

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

s.HandleFunc("/abc", handler.GetAbc).Methods("GET")
s.HandleFunc("/xyz", handler.GetXyz).Methods("GET")

我想使用日志中间件,但我不想在每一行都重复它,因为它们在 github 中显示:

r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
r.HandleFunc("/", ShowIndex)

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

【问题讨论】:

    标签: go router mux


    【解决方案1】:

    使用中间件:

    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)
    
    

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

    【讨论】:

    • 我想使用 gorilla 的 LoggingHandler。我把它包裹在一个中间件中
    【解决方案2】:

    我用中间件函数包装了 LoggingHandler

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

    【讨论】:

      【解决方案3】:

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

      
      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())
      }
      

      这样我就覆盖了我的基地:

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

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

      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
      

      【讨论】:

      • 似乎是一种有趣的方法。这个标准是 golang 社区的标准还是你“发明”的?
      • 尽管我想把功劳归于swagger.io,这是他们从 Swagger Doc 生成骨架的标准。大多数情况下,我编写 API,这些 API 是合同优先的,这使我能够生成不包括中间件的基本服务器结构。
      • @PraveenPremaratne 我们可以看看你的 LoggingHandler 吗?
      【解决方案4】:

      更紧凑的解决方案

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

      【讨论】:

        猜你喜欢
        • 2020-08-26
        • 2015-04-07
        • 2021-07-26
        • 2015-04-02
        • 2017-03-10
        • 2016-03-31
        • 2021-10-16
        • 1970-01-01
        • 2018-05-17
        相关资源
        最近更新 更多