英文:
How to use a middleware for a specific route, among other ones?
问题
我的简化路由与以下代码类似:
r.Route("/api/v1", func(r chi.Router) {
    r.Route("/case", func(r chi.Router) {
        // 通用案例 - 适用于所有人
        r.Get("/{uuid}", caseGetByUuid)
        r.Put("/", casePut)
        // 所有案例仅对管理员可用
        // r.Use(ensureAdminUser)  // ← 这是我遇到错误的地方
        r.Get("/", caseGetAll)
    })
    // 管理员端点
    r.Route("/admin", func(r chi.Router) {
        // 确保用户是管理员
        r.Use(ensureAdminUser)
        r.Route("/user", func(r chi.Router) {
            r.Route("/token", func(r chi.Router) { // /admin/user/token
                r.Get("/", userTokenGetAll)
                r.Put("/", userTokenCreate)
                r.Delete("/", userTokenDelete)
            })
        })
    })
})
第二个路由 (/admin) 受到一个中间件的限制,如果不满足特定条件,将中断链条。该中间件位于所有路由之前。
我希望在第一个路由 (/case) 中进行类似的过滤,但只针对其中的一个路由(三个路由中的一个)。取消注释 r.Use(ensureAdminUser) 会导致以下错误:
panic: chi: all middlewares must be defined before routes on a mux
我也不能为 /case 创建两个路由。
是否有办法保留 /case 路由并限制根调用的其中一种方法?
如果没有,我将为受限制的情况创建一个替代路由。
英文:
My simplified routing is similar to
r.Route("/api/v1", func(r chi.Router) {
		r.Route("/case", func(r chi.Router) {
            // generic case - for everyone
			r.Get("/{uuid}", caseGetByUuid)
			r.Put("/", casePut)
			// all cases only available to admins
			// r.Use(ensureAdminUser)  // ← this is the place I have an error
			r.Get("/", caseGetAll)
		}
		// admin endpoint
		r.Route("/admin", func(r chi.Router) {
			// ensure that the user is an admin
			r.Use(ensureAdminUser)
			r.Route("/user", func(r chi.Router) {
				r.Route("/token", func(r chi.Router) { // /admin/user/token
					r.Get("/", userTokenGetAll)
					r.Put("/", userTokenCreate)
					r.Delete("/", userTokenDelete)
				})
			})
		})
	})
The second route (/admin) is restricted by a middleware that will break the chain if specific constraints are not met. The middleware is placed ahead of all the routes.
I wanted to do similar filtering in the first route (/case), but only for one route (out of the three). Uncommenting r.Use(ensureAdminUser) leads to
panic: chi: all middlewares must be defined before routes on a mux
I cannot have two routes for /case either.
Is there a way to keep the route /case and restrict one of the methods for the root call?
If not I will create an alternative route for the restricted case.
答案1
得分: 2
你可以将中间件和后续的路由包装在它们自己的组中(我强调):
>// Group 在当前路由路径上添加一个新的内联路由器,
>// 并为内联路由器创建一个新的中间件栈。
>Group(fn func(r Router)) Router
    r.Route("/api/v1", func(r chi.Router) {
        r.Route("/case", func(r chi.Router) {
            // 通用案例 - 适用于所有人
            r.Get("/{uuid}", caseGetByUuid)
            r.Put("/", casePut)
            // 所有案例仅对管理员可用
            r.Group(func(r chi.Router) {
                r.Use(ensureAdminUser)
                r.Get("/", caseGetAll)
	        })
        }
    })
这也适用于使用r.Route创建的子路由器。
另一种选择是当中间件仅应用于一个路由时,可以使用r.With来“内联”中间件:
    r.Route("/api/v1", func(r chi.Router) {
        r.Route("/case", func(r chi.Router) {
            // 通用案例 - 适用于所有人
            r.Get("/{uuid}", caseGetByUuid)
            r.Put("/", casePut)
            // 所有案例仅对管理员可用
            r.With(ensureAdminUser).Get("/", caseGetAll)
        }
    })
英文:
You can wrap the middleware and subsequent routes in their own group (emphasis mine):
>// Group adds a new inline-Router along the current routing
>// path, with a fresh middleware stack for the inline-Route.
>Group(fn func(r Router)) Router
    r.Route("/api/v1", func(r chi.Router) {
        r.Route("/case", func(r chi.Router) {
            // generic case - for everyone
            r.Get("/{uuid}", caseGetByUuid)
            r.Put("/", casePut)
            // all cases only available to admins
            r.Group(func(r chi.Router) {
                r.Use(ensureAdminUser)
                r.Get("/", caseGetAll)
	        })
        }
    })
It will work also with a sub-router with r.Route.
Another option when a middleware is applied to only one route is r.With which allows you to “inline” the middleware:
r.Route("/api/v1", func(r chi.Router) {
    r.Route("/case", func(r chi.Router) {
        // generic case - for everyone
        r.Get("/{uuid}", caseGetByUuid)
        r.Put("/", casePut)
        // all cases only available to admins
        r.With(ensureAdminUser).Get("/", caseGetAll)
    }
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论