【问题标题】:HTTP handler functionHTTP 处理函数
【发布时间】:2018-02-28 09:13:42
【问题描述】:

我看到一些 http 处理函数的声明是多种多样的。 我发现其中两个是标准函数,一个是在处理程序中返回匿名函数。 例如:

使用标准方式:

func helloworld(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello World")
}

这是为 http api 声明处理程序的最直接方式。

另一种方法是在处理函数中使用匿名/闭包函数:

func helloworld2() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
        fmt.Fprintln(w, "Hello World")
    })
}

有什么区别和好处?何时使用其中之一?最佳做法是什么?

【问题讨论】:

标签: go httphandler


【解决方案1】:

图案

func Middleware(next http.Handler) http.Handler{
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // Do something
    next.ServeHTTP(w, r)
  })
}

常用于构造中间件链之类的

http.Handle("/", middlewareOne(middlewareTwo(finalHandler)))

【讨论】:

    【解决方案2】:

    返回一个匿名函数是处理需要额外参数的处理程序的唯一方法,方法是返回一个闭包。示例:

    func fooHandler(db *someDatabase) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // do something with `db` variable
        }
    }
    

    否则,这些方法之间通常没有实际区别。为了一致性,可以选择通用的匿名函数。

    【讨论】:

      【解决方案3】:

      关于结构返回匿名函数的最受欢迎的信息来源之一是 Mat Ryer How I write HTTP services after eight years 的博客文章

      我相信在这里提供他文章中的一些引用会很好:

      ...处理函数实际上并不处理请求,它们返回一个处理请求的函数。这为我们提供了一个闭包环境,我们的处理程序可以在其中运行:

      func (s *server) handleSomething() http.HandlerFunc {
          thing := prepareThing()
          return func(w http.ResponseWriter, r *http.Request) {
              // use thing        
          }
      }
      

      prepareThing 只被调用一次,所以你可以用它做一次 每个处理程序初始化,然后在处理程序中使用该事物。

      还有,

      如果端点有自己的请求和响应类型,通常它们只对特定的处理程序有用。如果是这种情况,您可以在函数中定义它们。

      func (s *server) handleSomething() http.HandlerFunc {
      
        // you have these handy structs always visible to your handler and eyes 
        // and invisible to code that don't use them
      
        type request struct {
          Name string
        }
      
        type response struct {
          Greeting string `json:"greeting"`
        }
      
        return func(w http.ResponseWriter, r *http.Request) {
          // decode into request struct
          // validate
          // call business-logic 
          // encode response from business-logic into response struct 
      
        }
      

      }

      在实践中,编写 RESTy API 你有以资源命名的处理程序,例如您有 /maps 资源和适当的处理程序 struct mapsHandler,其中注入了依赖项(存储库、包含一些业务逻辑的服务、记录器)。但有时您还需要为每个句柄专门传递一个额外的依赖项,然后突然意识到处理程序具有严格的签名,因此您应该将其包装起来。然后你就有了这样的东西

      // RESTy routes for "maps" resource
      router.Route("/maps", func(r chi.Router) {
          adHocDependency := newAdHocDependency(options)
          r.Post("/", mapsHandler.handleCreateMap(adHocDependency))
      })
      

      使您的临时依赖项对您的处理程序可见。

      希望对你有帮助!

      【讨论】:

        猜你喜欢
        • 2014-08-06
        • 2015-10-02
        • 2017-08-17
        • 1970-01-01
        • 2018-03-13
        • 1970-01-01
        • 1970-01-01
        • 2019-02-08
        • 2014-05-18
        相关资源
        最近更新 更多