对 echo 框架进行统一的自定义错误处理
借助移动端的增长,如今 RESTful 风格的 API 已经十分流行, ECHO 框架由于 golang 的标准库在网络方面已经很完善,导致框架发挥余地不大。很多高手都说,
这些特性里,HTTP/2,Auto HTTPS,听着很熟?这是我之前介绍的 Caddy 也有的特性, 其实今天我主要想说说最后一个特性里提到的,“中心化的 HTTP 错误处理”。 RESTful API 错误返回一个团队应当有一份 RESTful API 的规范,而在规范中应该规范响应格式,包括所有错误响应的格式。 STATUS 400 Bad Request { "error": "InvalidID","message": "invalid id in your url query parameters" } 传统的错误响应可能只有一个伴随 HTTP Status code 的 string 类型的 message, 好了,我们就用这个简单的例子进行下去,今天主题讲的是 Echo 去统一处理的方法。 Echo 怎么统一处理错误?其实 Echo 的文档虽然很漂亮,但是不够详细,深入一点的内容和例子并没有。 type Echo struct { Server *http.Server TLSServer *http.Server Listener net.Listener TLSListener net.Listener DisableHTTP2 bool Debug bool HTTPErrorHandler HTTPErrorHandler Binder Binder Validator Validator Renderer Renderer AutoTLSManager autocert.Manager Mutex sync.RWMutex Logger Logger // contains filtered or unexported fields } 果然可以定义 HTTPErrorHandler,顺着找过去, // HTTPErrorHandler is a centralized HTTP error handler. type HTTPErrorHandler func(error,Context) 它是一个传入 error 和 Context 并且没有返回值的函数。 定义错误结构由于 golang 是静态类型,我们干啥都需要先定义个结构,代码如下: type httpError struct { code int Key string `json:"error"` Message string `json:"message"` } func newHTTPError(code int,key string,msg string) *httpError { return &httpError{ code: code,Key: key,Message: msg,} } // Error makes it compatible with `error` interface. func (e *httpError) Error() string { return e.Key + ": " + e.Message } 这里我们做了三件事
处理错误我们终于可以写上文提到的自定义函数了,先看示例代码我再做解释,然后你就能写自己的了: package main import ( "net/http" "github.com/labstack/echo" ) // httpErrorHandler customize echo's HTTP error handler. func httpErrorHandler(err error,c echo.Context) { var ( code = http.StatusInternalServerError key = "ServerError" msg string ) if he,ok := err.(*httpError); ok { code = he.code key = he.Key msg = he.Message } else if ee,ok := err.(*echo.HTTPError); ok { code = ee.Code key = http.StatusText(code) msg = key } else if config.Debug { msg = err.Error() } else { msg = http.StatusText(code) } if !c.Response().Committed { if c.Request().Method == echo.HEAD { err := c.NoContent(code) if err != nil { c.Logger().Error(err) } } else { err := c.JSON(code,newHTTPError(code,key,msg)) if err != nil { c.Logger().Error(err) } } } } 这个函数的功能就是根据传进来的 error 和上下文 Context,组装出合适的 HTTP 响应。 第一部分我们定义了默认值作为最坏的情况,在 HTTP API 里,消费端要是看到这种最坏的情况, 第二部分我们先看看传进来的错误是不是我们之前定义的,如果是那就太好了。如果不是的话, 第三部分你可以基本照抄,是检查上下文中是否声明这个响应已经提交了,只有没提交的时候, 应用好了,我们写好了统一的错误处理,该怎么使用呢? 来看一个极简的例子吧: func getUser(c echo.Context) error { var u user id := c.Param("id") if !bson.IsObjectIdHex(id) { return newHTTPError(http.StatusBadRequest,"InvalidID","invalid user id") } err := db.C("user").FindId(bson.ObjectIdHex(id)).One(&u) if err == mgo.ErrNotFound { return newHTTPError(http.StatusNotFound,"NotFound",err.Error()) } if err != nil { return err } return c.JSON(http.StatusOK,u) } 这是个从 mongodb 取 user 的例子,
我们可以看出,经过这么一番折腾,在写API的时候,省心了很多。 怎么样?快去安利小伙伴们用 echo 写 HTTP API 吧,真的很方便。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |