這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
前言
golang的error處理一直被人詬病,其實通過設計模式可以很好的處理error,這裡就以restful開發為例講下error優雅的處理
resuful開發中,error處理有兩個目的,一可以將錯誤資訊返回給使用者,二要方便調試,為了達到優雅還要一點,不要到處都是各種if語言
當然作為優雅的代碼還有一點要保證,就是盡量不寫重複的代碼
panic處理
在這裡我們把panic處理一下,把panic的if判斷也封裝到一個方法裡,並且包裹上堆棧資訊(這裡用到了github.com/pkg/errors包,具體使用在這裡就不贅述了,可以看github上的文檔),方便調試:
func ThrowError(err error) { if err != nil { panic(errors.WithStack(err)) }}
我們調用的時候相當簡單
// MarshalJson 把對象以json格式放到response中func MarshalJson(w http.ResponseWriter, v interface{}) { data, err := json.Marshal(v) ThrowError(err) w.Write(data)}// UnMarshalJson 從request中取出對象func UnMarshalJson(req *http.Request, v interface{}) { result, err := ioutil.ReadAll(req.Body) err = errors.New("TEST") ThrowError(err) json.Unmarshal([]byte(bytes.NewBuffer(result).String()), v)}
這樣就把一個錯誤逐級上拋,直到遇到處理的recover
revocer處理
我們把相應的recover也封裝了一下
func CatchError(w http.ResponseWriter, req *http.Request) { if r := recover(); r != nil { resp := &model.Resp{Code: "9001", Msg: r.(error).Error()} MarshalJson(w, resp) fmt.Printf("%+v\n", r.(error)) }}
把錯誤返回給使用者,並且列印錯誤的資訊,包括堆棧
統一處理
作為restful統一處理的地方,一般都是ServeHttp方法,但是如果用了第三方mux,強行改源碼不太雅觀,而且mux也有升級的時候,總不能升級一次改一次吧,那麼這裡使用一種封裝的方法
type MyRouter struct { *mux.Router}func (r *MyRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { defer tools.CatchError(w, req) r.Router.ServeHTTP(w, req)}func NewAPIMux() http.Handler { r := &MyRouter{mux.NewRouter()} s := r.PathPrefix("/api").Subrouter() initUserApi(s) r.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("web/")))) return r}
如此這般,error就優雅的處理了,無論任何地方,只需要按業務調用ThrowError方法,用戶端就可以收到錯誤資訊,服務端還可以同時列印錯誤的堆棧資訊
樣本輸出