Negroni продолжает вызывать другие обработчики после завершения запроса - PullRequest
0 голосов
/ 03 мая 2018

Мое веб-приложение в Go (использующее Gorilla mux и negroni) имеет около 20 обработчиков, разделенных на три группы в зависимости от того, какие функции Middleware следует применять. В частности:

  • Группа 1: Статические запросы (никакого промежуточного программного обеспечения вообще)

    GET   /favicon.ico
    GET   /files
    GET   /files/index.html
    GET   /files/favicon.ico
    
  • Группа 2: Запросы, которые должны иметь только промежуточное программное обеспечение CORS, без аутентификации:

    GET   /
    GET   /login
    POST  /login
    GET   /auth-configuration
    GET   /service-status
    
  • Группа 3: Запросы, к которым должны применяться как CORS, так и промежуточное ПО аутентификации:

    GET   /articles
    POST  /articles
    PUT   /articles/etc
    PATCH /articles/etc
    

Это мой код, который устанавливает HTTP-сервер:

func run() {

    negroniStack := setUpNegroni()

    bindAddr := // ...

    http.ListenAndServe(bindAddr, negroniStack)
}

func setUpNegroni() negroni.Negroni {

    negroniStack := negroni.Negroni{}

    staticNegroni := setUpRoutesAndMiddlewareForStaticRequests()
    loginNegroni  := setUpRoutesAndMiddlewareForLogin()
    serviceNegroni = setUpRoutesAndMiddlewareForService()

    negroniStack.UseHandler(&staticNegroni)
    negroniStack.UseHandler(&loginNegroni)
    negroniStack.UseHandler(&serviceNegroni)

    return negroniStack
}

func setUpRoutesAndMiddlewareForStaticRequests() negroni.Negroni {

    staticNegroni := negroni.Negroni{}
    staticRouter := mux.NewRouter()

    staticRouter.PathPrefix("/files").HandlerFunc(staticHandler)
    staticRouter.Path("/favicon.ico").HandlerFunc(staticHandler)

    staticNegroni.UseHandler(staticRouter)
    return staticNegroni
}

func setUpRoutesAndMiddlewareForLogin() negroni.Negroni {

    authNegroni := negroni.Negroni{}

    corsMiddleware := cors.New(cors.Options{
        AllowedMethods:     []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"},
        AllowCredentials:   true,
        OptionsPassthrough: false,
    })

    authNegroni.Use(corsMiddleware)

    authRouter := mux.NewRouter()

    authRouter.HandleFunc("/login", HandlePostAuth).Methods("POST")
    authRouter.HandleFunc("/login", HandleGetAuth) // GET

    authNegroni.UseHandler(authRouter)

    return authNegroni
}

func setUpRoutesAndMiddlewareForService() negroni.Negroni {

    serviceNegroni := negroni.Negroni{}

    corsMiddleware := cors.New(cors.Options{
        AllowedMethods:     []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"},
        AllowCredentials:   true,
        OptionsPassthrough: false,
    })
    serviceNegroni.Use(corsMiddleware)

    serviceNegroni.UseFunc(jwtMiddleware)

    serviceRouter := mux.NewRouter()
    serviceRouter.HandleFunc("/articles", HandleGetArticles).Methods("GET")
    serviceRouter.HandleFunc("/articles", HandlePostArticles).Methods("POST")
    // etc

    serviceNegroni.UseHandler(serviceRouter)

    return serviceNegroni
}

Я считаю, что это правильно, основываясь на разделе «Маршрутное промежуточное программное обеспечение» в документации Negroni , где говорится:

Если у вас есть группа маршрутов, для которой требуется выполнение определенного промежуточного программного обеспечения, вы можете просто создать новый экземпляр Negroni и использовать его в качестве обработчика маршрута.

Однако, когда я делаю запросы и использую отладчик, я вижу, что (*Negroni).ServeHTTP вызывается несколько раз. Например, если я запрашиваю GET /favicon.ico, то функция staticHandler вызывается правильно и вызывает WriteHeader(200), но после этого она затем вызывает следующий mux.Router, который вызывает WriteHeader(404), который выводит предупреждение в терминал, потому что заголовок был написан дважды (http: multiple response.WriteHeader calls)

Если это маршрут, который не существует, то по умолчанию Gorilla NotFoundHandler вызывается 3 раза (по одному на каждый mux.Router).

Как заставить Negroni прекратить вызывать другие обработчики после того, как запрос был выполнен?

... и если я неправильно настроил свой экземпляр Negroni, почему он не выполняет проверки во время инициализации, чтобы предупредить меня о неверной конфигурации?

Насколько я понимаю, negroni.Use и UseFunc предназначены для установки промежуточного программного обеспечения (все они вызываются для каждого запроса), а UseHandler для настройки обработчика терминала (только 1 вызывается для каждого запроса). или отступление до 404). Если я правильно понимаю ситуацию, то по какой-то причине он обрабатывает мои терминальные обработчики как промежуточное ПО.

1 Ответ

0 голосов
/ 03 мая 2018

Из документации UseHandler (https://godoc.org/github.com/urfave/negroni#Negroni.UseHandler)

UseHandler добавляет http.Handler в стек промежуточного программного обеспечения. Обработчики вызываются в порядке их добавления в Negroni.

Так что, похоже, вы видите здесь ожидаемое поведение.

В основном вы создаете разные экземпляры негрони и объединяете их в цепочки, поэтому ваш окончательный negroniStack сам является промежуточным программным обеспечением, которое будет выполнять другие промежуточные программы, которые вы добавили.

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

Если вы посмотрите на пример, который вы связали из документов, это то, что они делают в этом разделе (https://github.com/urfave/negroni#route-specific-middleware).

router.PathPrefix("/admin").Handler(negroni.New(
   Middleware1,
   Middleware2,
   negroni.Wrap(adminRoutes),
))

Обратите внимание, что они не являются вложенными экземплярами негрони, а скорее создают только тот, который применяется к желаемым маршрутам.

...