英文:
Setting up Route Not Found in Gin
问题
我已经在Gin中设置了默认路由和一些路由:
router := gin.Default()
router.POST("/users", save)
router.GET("/users", getAll)
但是如何处理Gin中的404 Route Not Found呢?
最初,我使用的是httprouter,我知道Gin也使用它,所以最初的代码是这样的:
router.NotFound = http.HandlerFunc(customNotFound)
以及函数:
func customNotFound(w http.ResponseWriter, r *http.Request) {
// 返回JSON
return
}
但是这种方法在Gin中不起作用。
我需要能够使用c *gin.Context
返回JSON,这样我就可以使用:
c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
英文:
I've setup a default router and some routes in Gin:
router := gin.Default()
router.POST("/users", save)
router.GET("/users",getAll)
but how do I handle 404 Route Not Found in Gin?
Originally, I was using httprouter which I understand Gin uses so this was what I originally had...
router.NotFound = http.HandlerFunc(customNotFound)
and the function:
func customNotFound(w http.ResponseWriter, r *http.Request) {
//return JSON
return
}
but this won't work with Gin.
I need to be able to return JSON using the c *gin.Context
so that I can use:
c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
答案1
得分: 70
你要找的是NoRoute
处理程序。
更具体地说:
r := gin.Default()
r.NoRoute(func(c *gin.Context) {
c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "页面未找到"})
})
英文:
What you're looking for is the NoRoute
handler.
More precisely:
r := gin.Default()
r.NoRoute(func(c *gin.Context) {
c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
})
答案2
得分: 3
根据Pablo Fernandez的写法,我还看到可以使用405 MethodNotAllowed来实现相同的效果,所以类似于404的NoRoute,405对应的是NoMethod方法。
所以,以下是结果:
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func main() {
app := gin.New()
app.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"code": "PAGE_NOT_FOUND", "message": "404 page not found"})
})
app.NoMethod(func(c *gin.Context) {
c.JSON(http.StatusMethodNotAllowed, gin.H{"code": "METHOD_NOT_ALLOWED", "message": "405 method not allowed"})
})
}
为了添加一个“catch all”方法,我们可以这样做:
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func main() {
app := gin.New()
app.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"code": "PAGE_NOT_FOUND", "message": "404 page not found"})
})
app.NoMethod(func(c *gin.Context) {
c.JSON(http.StatusMethodNotAllowed, gin.H{"code": "METHOD_NOT_ALLOWED", "message": "405 method not allowed"})
})
}
// 设置错误处理中间件
app.Use(func(c *gin.Context) {
log.Printf("Total Errors -> %d", len(c.Errors))
if len(c.Errors) <= 0 {
c.Next()
return
}
for _, err := range c.Errors {
log.Printf("Error -> %+v\n", err)
}
c.JSON(http.StatusInternalServerError, "")
})
现在,gin只有这两个方法用于处理这两种类型的错误,我猜这是因为在构建API时这两种错误是最常见的,并且希望在首次设置应用程序时添加一些默认处理程序。
实际上,我们可以在这里看到实现:
// NoRoute添加NoRoute的处理程序。默认情况下返回404代码。
func NoRoute(handlers ...gin.HandlerFunc) {
engine().NoRoute(handlers...)
}
// NoMethod是Engine.NoMethod的包装器。
func NoMethod(handlers ...gin.HandlerFunc) {
engine().NoMethod(handlers...)
}
现在,默认情况下,当使用gin框架的用户没有使用这两个处理程序时,它们使用的默认主体在这里定义:
var (
default404Body = []byte("404 page not found")
default405Body = []byte("405 method not allowed")
)
然后在函数handleHTTPRequest
中使用,从632行开始:
if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees {
if tree.method == httpMethod {
continue
}
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
}
}
}
c.handlers = engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body)
}
英文:
Adding to what Pablo Fernandez wrote I also seen that the same can be done with 405 MethodNotAllowed, so similarly if for 404 we've got NoRoute for 405 there is NoMethod method
So having this as result
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func main() {
app := gin.New()
app.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"code": "PAGE_NOT_FOUND", "message": "404 page not found"})
})
app.NoMethod(func(c *gin.Context) {
c.JSON(http.StatusMethodNotAllowed, gin.H{"code": "METHOD_NOT_ALLOWED", "message": "405 method not allowed"})
})
}
In order to add a 'catch all' method we can do:
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func main() {
app := gin.New()
app.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"code": "PAGE_NOT_FOUND", "message": "404 page not found"})
})
app.NoMethod(func(c *gin.Context) {
c.JSON(http.StatusMethodNotAllowed, gin.H{"code": "METHOD_NOT_ALLOWED", "message": "405 method not allowed"})
})
}
// Set-up Error-Handler Middleware
app.Use(func(c *gin.Context) {
log.Printf("Total Errors -> %d", len(c.Errors))
if len(c.Errors) <= 0 {
c.Next()
return
}
for _, err := range c.Errors {
log.Printf("Error -> %+v\n", err)
}
c.JSON(http.StatusInternalServerError, "")
})
Now, gin has these 2 method only for these 2 type of errors,my guess is because are the most common one while building an API and wanted to add some default handler when you first set up the application.
In fact, we can see the implementation here:
// NoRoute adds handlers for NoRoute. It returns a 404 code by default.
func NoRoute(handlers ...gin.HandlerFunc) {
engine().NoRoute(handlers...)
}
// NoMethod is a wrapper for Engine.NoMethod.
func NoMethod(handlers ...gin.HandlerFunc) {
engine().NoMethod(handlers...)
}
Now, the body that uses by default when these 2 handlers are not used by who uses the gin framework (so the default one are) are defined enter link description here
var (
default404Body = []byte("404 page not found")
default405Body = []byte("405 method not allowed")
)
And then later on used on the function handleHTTPRequest
from line 632
if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees {
if tree.method == httpMethod {
continue
}
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
}
}
}
c.handlers = engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论