【发布时间】:2018-05-03 10:56:41
【问题描述】:
我在 Go 中的 Web 应用程序(使用 Gorilla mux 和 negroni)有大约 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's documentation 中的“路由特定中间件”部分,我认为这是正确的:
如果您有一组需要执行特定中间件的路由,您可以简单地创建一个新的 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)。如果我正确理解这种情况,那么出于某种原因,它会将我的终端处理程序视为中间件。
【问题讨论】:
-
这里有完整的路线列表吗?你有像“/{category}”这样的路线吗?
-
@vitr 我可以使用此处发布的代码重现该问题。