请求完成后,内格罗尼继续调用其他处理程序



我在Go中的Web应用程序(使用Gorillamuxnegroni(有大约20个处理程序,根据应该应用的中间件功能分为三组。具体说来:

  • 组 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),但之后它会调用下一个调用WriteHeader(404)的下一个mux.Router,该在终端中打印出警告,因为标头被写入了两次(http: multiple response.WriteHeader calls(

如果它适用于不存在的路由,则调用大猩猩默认NotFoundHandler3 次(每个mux.Router一次(。

如何让 Negroni 在请求完成后停止调用其他处理程序?

。如果我错误地配置了我的 Negroni 实例,为什么它在初始化期间不执行检查以警告我配置无效?

我的理解是,negroni.UseUseFunc用于设置中间件(每个请求都会调用(,而UseHandler是设置终端处理程序(每个请求仅调用 1,或回退到 404(。如果我正确理解了这种情况,那么出于某种原因,它将我的终端处理程序视为中间件。

来自UseHandler文档 (https://godoc.org/github.com/urfave/negroni#Negroni.UseHandler(

UseHandler 添加一个 http。处理程序到中间件堆栈上。处理程序按照它们添加到黑人的顺序调用。

因此,您在这里看到的似乎是预期的行为。

您基本上是在创建不同的 negroni 实例并将它们链接起来,因此您的最终negroniStack是一个中间件本身,它将执行您添加的其他中间件。

我相信您要做的是使用实际路由器创建路由,然后将适当的中间件(使用 negroni(添加到每个路由。

如果您查看从文档中链接的示例,这就是他们在该部分(https://github.com/urfave/negroni#route-specific-middleware(中所做的。

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

看到它们不是嵌套 negroni 实例,而是只创建一个应用于所需路由

的实例。

最新更新