Можно ли использовать собственный обработчик HTTP глобально при использовании Negroni или только для каждого запроса?

Чтобы убедиться, что результаты ошибок обрабатываются правильно для всех запросов, я реализую собственный обработчик, как описано в http://blog.golang.org/error-handling-and-go. Таким образом, вместо того, чтобы принимать только параметры w http.ResponseWriter, r *http.Request, обработчик необязательно возвращает error.

Я использую 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)
}

person klotz    schedule 29.08.2015    source источник


Ответы (1)


Вы можете написать обертку вокруг r.Handle, если хотите. Вы не можете сделать это глобально с Negroni, поскольку не все промежуточное ПО, которое вы используете, предполагает ваш тип handler.

e.g.

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

Я бы сказал, что это не намного лучше, чем просто явное приведение типов ваших обработчиков (что ясно, хотя и немного повторяющееся) или превращение вашего типа обработчика в структуру. Последний вы можете позже расширить, чтобы он содержал потокобезопасные поля (ваш пул БД, конфигурация приложения и т. д.), которые вы затем можете явно передать вместе с каждым обработчиком).

На самом деле ваш текущий код маршрутизатора по-прежнему ясен и легко читается, и делает очевидным (для других), какой тип лежит в основе ваших обработчиков.

person elithrar    schedule 30.08.2015