我想獲取每條路由上的所有 http 錯誤,而無需每次都重寫 if 400 then if 404 then if 500 then etc...所以我ErrorHandler()在每個路由處理程式中有一個函式:
func (h *Handler) List(c *gin.Context) {
movies, err := h.service.ListService()
if err != nil {
utils.ErrorHandler(c, err)
return
}
c.JSON(http.StatusOK, movies)
}
這個函式看起來像這樣:
func ErrorHandler(c *gin.Context, err error) {
if err == ErrNotFound {
// 404
c.JSON(http.StatusNotFound, gin.H{"error": ErrNotFound.Error()})
} else if err == ErrInternalServerError {
// 500
c.JSON(http.StatusInternalServerError, gin.H{"error": ErrInternalServerError.Error()})
} // etc...
}
ErrNotFound或者ErrInternalServerError只是像這樣初始化的全域變數:
var ErrNotFound = errors.New(http.StatusText(http.StatusNotFound)) // 404
我想知道我是否做得對,或者是否有更好的方法來執行此操作,例如獲取中間件中的錯誤并直接回傳回應?
使用 node.js 我能夠發送err中間件引數并像這樣使用它:
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof HttpError) {
res.status(err.status).json({error: err.message});
} else if (err instanceof Error) {
res.status(500).json({error: err.message});
} else {
res.status(500).send("Internal Server Error");
}
});
有沒有類似的?
uj5u.com熱心網友回復:
utils使用中間件比使用函式更慣用(作為包名也不受歡迎):
func ErrorHandler(c *gin.Context) {
c.Next()
for _, err := range c.Errors {
// log, handle, etc.
}
c.JSON(http.StatusInternalServerError, "")
}
func main() {
router := gin.New()
router.Use(middleware.ErrorHandler)
// ... routes
}
值得注意的是,您在實際錯誤處理代碼之前呼叫c.Next()中間件 func ,因此您可以確保在呼叫處理程式鏈的其余部分之后進行錯誤處理。
Next 應該只在中間件內部使用。它在呼叫處理程式內執行鏈中的掛起處理程式。[...]
使用中間件的好處是,你還可以傳遞引數給它,例如記錄器,你可能以后要使用的錯誤處理,部分曾經,而不是每次呼叫時間的推移它utils.ErrorHandler直接。在這種情況下,它看起來像這樣(我使用 Uber Zap 記錄器):
func ErrorHandler(logger *zap.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
for _, ginErr := range c.Errors {
logger.Error("whoops", ...)
}
}
}
func main() {
router := gin.New()
logger, _ := zap.NewDevelopment()
router.Use(middleware.ErrorHandler(logger))
// ... routes
}
然后處理程式將只是中止鏈,而不是呼叫一個函式,這看起來更干凈,更容易維護:
func (h *Handler) List(c *gin.Context) {
movies, err := h.service.ListService()
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusOK, movies)
}
如果您在設定HTTP狀態這是需要注意的重要c.AbortWithStatus或者c.AbortWithError,您可能希望不是在錯誤處理程式覆寫它。在這種情況下,您可以c.JSON()使用-1狀態代碼呼叫:
func ErrorHandler(logger *zap.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
for _, ginErr := range c.Errors {
logger.Error("whoops", ...)
}
// status -1 doesn't overwrite existing status code
c.JSON(-1, /* error payload */)
}
}
Lastly, using a middleware allows you to call c.Error in your handlers multiple times, e.g. when a series of non-fatal errors occur and you want to capture all of them before actually aborting the request.
Error attaches an error to the current context. The error is pushed to a list of errors. It's a good idea to call Error for each error that occurred during the resolution of a request. A middleware can be used to collect all the errors and [process them]
func (h *Handler) List(c *gin.Context) {
err1 := /* non-fatal error */
if err1 != nil {
c.Error(err1)
}
err2 := /* another non-fatal error */
if err2 != nil {
c.Error(err2)
}
fatalErr := /* fatal error */
if fatalErr != nil {
c.AbortWithError(505, fatalErr)
return
// the error handler will have collected all 3 errors
}
c.JSON(http.StatusOK, movies)
}
As for the actual error handling in the middleware, it's pretty straightforward. Just remember that all calls to c.Error, c.AbortWith... will wrap your error in a gin.Error. So to inspect the original value you have to check the err.Err field:
func ErrorHandler(c *gin.Context) {
c.Next()
for _, err := range c.Errors {
switch err.Err {
case ErrNotFound:
c.JSON(-1, gin.H{"error": ErrNotFound.Error()})
}
// etc...
}
c.JSON(http.StatusInternalServerError, "")
}
Iterating over c.Errors may seem unwieldy because now you have potentially N errors instead of one, but depending on how you intend to use the middleware, you can simply check len(c.Errors) > 0 and access only the first item c.Errors[0].
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/358306.html
