英文:
How to preserve path params after handling a request with router.Any and wildcard
问题
在我的情况下,需要捕获请求并检查是否为内部请求。如果不是,则将这些请求重定向到其他处理程序函数。
URL示例:
1. URL: http://localhost/internal/dosomething1
2. URL: http://localhost/internal/dosomething2/:id
3. URL: http://localhost/overview
4. URL: http://localhost/xxx
只有以 internal
开头的 URI 应该在我的处理函数中处理(案例 1 和 2)。
其他任何请求方法的 URI 都将代理到另一个函数(案例 3 和 4)。
我尝试使用 router.Any("/*uri", handlerExternal)
,代码如下:
func handlerExternal(c *gin.Context) {
path := c.Param("uri")
if strings.HasPrefix(path, "/internal/") {
uri := strings.Split(path, "/")
switch uri[2] {
case "dosomething1":
doInternal(c)
}
} else {
doExternal(c)
}
}
但是,使用这种解决方案时,doInternal(c)
无法捕获像 http://localhost/internal/dosomething2/:id
中的路径参数 :id
。
在这种情况下,是否有更好的解决方案?
英文:
In my case need to catch request and check is internal request or not. If not, redirect these request to other handler function.
URL example:
1. URL: http://localhost/internal/dosomething1
2. URL: http://localhost/internal/dosomething2/:id
3. URL: http://localhost/overview
4. URL: http://localhost/xxx
Only the URIs that start with internal
should be handled in my own handle function (cases 1 and 2).
Others with any request method will proxy to another function (cases 3 and 4).
I am trying to use router.Any("/*uri", handlerExternal)
as such:
func handlerExternal(c *gin.Context) {
path := c.Param("uri")
if strings.HasPrefix(path, "/internal/") {
uri := strings.Split(path, "/")
switch uri[2] {
case "dosomething1":
doInternal(c)
}
} else {
doExternal(c)
}
}
But with this solution, the doInternal(c)
cannot catch path parameters like :id
as in http://localhost/internal/dosomething2/:id
Is there any better solution for this case?
答案1
得分: 0
使用子引擎。
您可以使用gin.New
实例化一个引擎,仅用于内部路由,而不运行它。相反,您将上下文从您的Any
路由传递给Engine.HandleContext
。
这将传递主引擎的上下文,并根据子路由中的占位符匹配路径参数。
您可以像往常一样在子引擎上声明路由:
func main() {
internalEngine := gin.New()
internalEngine.GET("/internal/dosomething1", func(c *gin.Context) { c.JSON(200, "ok") })
internalEngine.GET("/internal/dosomething2/:id", func(c *gin.Context) { c.JSON(200, c.Param("id")) })
mainEngine := gin.New()
mainEngine.Any("/*uri", func(c *gin.Context) {
path := c.Param("uri")
if strings.HasPrefix(path, "/internal/") {
uri := strings.Split(path, "/")
switch uri[2] {
case "dosomething1", "dosomething2":
internalEngine.HandleContext(c)
}
} else {
doExternal(c)
}
})
mainEngine.Run(":8800")
}
您还可以在将上下文传递给子引擎之前修改c.Request.URL.Path
,例如,通过删除internal
前缀。
现在,如果您尝试向以下地址发送GET请求:
http://localhost:8855/internal/dosomething2/1234
它将返回以下输出:
"1234"
英文:
Use a sub-engine.
You can instantiate an engine with gin.New
for internal routes only and not run it. Instead you pass the context from your Any
route to Engine.HandleContext
.
This will relay the context from the main engine, and it will match path params based on the placeholders in the sub-routes.
You can declare routes on the sub-engine as usual:
func main() {
internalEngine := gin.New()
internalEngine.GET("/internal/dosomething1", func(c *gin.Context) { c.JSON(200, "ok") })
internalEngine.GET("/internal/dosomething2/:id", func(c *gin.Context) { c.JSON(200, c.Param("id")) })
mainEngine := gin.New()
mainEngine.Any("/*uri", func(c *gin.Context) {
path := c.Param("uri")
if strings.HasPrefix(path, "/internal/") {
uri := strings.Split(path, "/")
switch uri[2] {
case "dosomething1", "dosomething2":
internalEngine.HandleContext(c)
}
} else {
doExternal(c)
}
})
mainEngine.Run(":8800")
}
You can also modify c.Request.URL.Path
before relaying the context to the sub-engine, e.g. by removing the internal
prefix, if so you wish.
Now if you try a GET request to:
http://localhost:8855/internal/dosomething2/1234
it will echo the output:
"1234"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论