简体   繁体   English

使用Negroni时,可以仅在每个请求中全局使用自定义HTTP处理程序吗?

[英]Can a custom HTTP handler be used globally when using Negroni or only per request?

To make sure error results are handled correctly across all requests I'm implementing a custom handler as described in http://blog.golang.org/error-handling-and-go . 为了确保在所有请求中正确处理错误结果,我正在实现自定义处理程序,如http://blog.golang.org/error-handling-and-go中所述 So instead of only accepting the w http.ResponseWriter, r *http.Request params the handler optionally returns an error . 因此w http.ResponseWriter, r *http.Request参数不仅接受w http.ResponseWriter, r *http.Request可选地返回error

I'm using Negroni and wondered whether I can set it up once to wrap all requests into handler or if it will always have to be set up on a per-request basis as done for / and /foo in the following example? 我正在使用Negroni,想知道是否可以将其设置一次以将所有请求包装到handler或者是否始终必须像下面的示例中对//foo在每个请求的基础上进行设置?

type handler func(w http.ResponseWriter, r *http.Request) error

// ServeHTTP checks for error results and handles them globally
func (fn handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if err := fn(w, r); err != nil {
        http.Error(w, err, http.StatusInternalServerError)
    }
}

// Index matches the `handler` type and returns an error
func Index(w http.ResponseWriter, r *http.Request) error {
    return errors.New("something went wrong")
}

func main() {
    router := mux.NewRouter()
    // note how `Index` is wrapped into `handler`. Is there a way to 
    // make this global? Or will the handler(fn) pattern be required 
    // for every request?
    router.Handle("/", handler(Index)).Methods("GET")
    router.Handle("/foo", handler(Index)).Methods("GET")

    n := negroni.New(
        negroni.NewRecovery(),
        negroni.NewLogger(),
        negroni.Wrap(router),
    )

    port := os.Getenv("PORT")
    n.Run(":" + port)
}

You can write a wrapper around r.Handle if you want. 您可以根据需要在r.Handle周围编写包装器。 You can't do it globally with Negroni as not all middleware you use assumes your handler type. 您不能使用Negroni进行全局操作,因为并非您使用的所有中间件都假定您的handler类型。

eg 例如

// Named to make the example clear.
func wrap(r *mux.Router, pattern string, h handler) *mux.Route {
    return r.Handle(pattern, h)
}

func index(w http.ResponseWriter, r *http.Request) error {
    io.WriteString(w, "Hello")
    return nil
}

func main() {
    r := mux.NewRouter()
    wrap(r, "/", index)

    http.ListenAndServe(":8000", r)
}

I'd argue that this is not much better than just explicitly type-casting your handlers (which is clear, if a little repetitive), or turning your handler type into a struct. 我认为这不仅仅只是显式地类型转换您的处理程序(如果有一点重复,这是显而易见的),或者将您的处理程序类型转换为结构并没有多大好处。 The latter you can later extend to contain thread-safe fields (your DB pool, app config, etc) that you can then explicitly pass alongside each handler). 您可以稍后扩展后者以包含线程安全字段(您的数据库池,应用程序配置等),然后可以将其显式传递给每个处理程序。

In reality your current router code is still clear and easy to read, and makes it obvious (to others) what type underpins your handlers. 实际上,您当前的路由器代码仍然清晰易读,并使(对于其他人)显而易见的类型支持您的处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM