How to refactor error handling in go properly?

huangapple go评论85阅读模式
英文:

How to refactor error handling in go properly?

问题

我刚开始学习Go语言,所以还不习惯它的模式。

我有一个作为代理的Web服务器,用于访问其他远程服务。我正在使用mux将路由映射到处理程序,代码是在App Engine上运行的。

// imports omitted.

func init() {
  m = mux.NewRouter()
  m.HandleFunc("/ponies", listPonies)
  m.HandleFunc("/rainbows", listRainbows)
  http.Handle("/", m)
}

func listPonies(w http.ResponseWriter, r *http.Request) {
  ponies, err := ponyService.getAll()
   
  if err != nil {
      w.write(err.Error())
      return;
  }

  w.write(string(ponies))
}

func listRainbows(w http.ResponseWriter, r *http.Request) {
  rainbows, err := rainbowService.getAll()
   
  if err != nil {
      w.write(err.Error())
      return;
  }

  w.write(string(rainbows))
}

我想将通用代码(错误处理、转换为字符串和写入响应)重构为一个单独的函数。

我的第一次尝试是简单地定义一个通用函数来调用:

func handleErrorAndWriteResponse(w http.ResponseWriter, obj Stringer, err error) {
  if err != nil {
      w.write(err.Error())
      return;
  }

  w.write(string(obj))
}

然后像这样调用它:

func listPonies(w http.ResponseWriter, r *http.Request) {
  handleErrorAndWriteResponse(w, ponyService.getAll())       
}

func listRainbows(w http.ResponseWriter, r *http.Request) {
  handleErrorAndWriteResponse(w, rainbowService.getAll())
}

但是:

  1. 它不起作用。我得到一个insufficient arguments错误。这可能与混合使用多个服务的多个响应值,而这些值不能直接转换为被调用函数的参数有关。
  2. 我不喜欢传递错误参数的想法。也许这没问题,只是看起来有点乱。不过,我对Go还不太了解。

有没有什么“正确的方法”(或者说Go的方法)来做到这一点呢?

英文:

I'm just starting with Go so I'm still not used to its patterns.

I have a web server that serves as a proxy to other remote services. I'm using mux to map routes to handlers, the code it's using App Engine.

// imports ommited.

func init() {
  m = mux.NewRouter()
  m.HandleFunc("/ponies", listPonies)
  m.HandleFunc("/rainbows", listRainbows)
  http.Handle("/", m)
}

func listPonies(w http.ResponseWriter, r *http.Request) {
  ponies, err := ponyService.getAll()
   
  if err != nil {
      w.write(err.Error())
      return;
  }

  w.write(string(ponies))
}

func listRainbows(w http.ResponseWriter, r *http.Request) {
  rainbows, err := rainbowService.getAll()
   
  if err != nil {
      w.write(err.Error())
      return;
  }

  w.write(string(rainbows))
}

I would like to refactor the common code (error handling, converting to string and writing the response) into a single function.

My first attempt was simply defining a common function to call:

func handleErrorAndWriteResponse(w http.ResponseWriter, obj Stringer, err error) {
  if err != nil {
      w.write(err.Error())
      return;
  }

  w.write(string(obj))
}

And call it like this

func listPonies(w http.ResponseWriter, r *http.Request) {
  handleErrorAndWriteResponse(w, ponyService.getAll())       
}

func listRainbows(w http.ResponseWriter, r *http.Request) {
  handleErrorAndWriteResponse(w, rainbowService.getAll())
}

But

  1. It doesn't work. I get an insufficient arguments error. It probably has to do with mixing the multiple response values from the services that don't translate directly into arguments of the function called.
  2. I don't like the idea of passing the error arguments around. Maybe that's fine, it just looks dirty to me. Then again, I don't know much about Go yet.

What's the "right way" (or the Go way) to do this?

答案1

得分: 4

有一篇关于在AppEngine应用程序中处理错误的博客文章,详细介绍了错误处理。特别是要查看“简化重复错误处理”部分。

处理错误的方法基本上是让处理函数在失败的情况下返回一个error,然后用通用的错误处理程序包装对它们的调用:

type appHandler func(http.ResponseWriter, *http.Request) error

func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if err := fn(w, r); err != nil {
        http.Error(w, err.Error(), 500)
    }
}

func listPonies(w http.ResponseWriter, r *http.Request) error {
    ponies, err := ponyService.getAll()

    if err != nil {
        return err;
    }

    w.write(string(ponies))
}

你还需要以不同的方式注册你的处理程序:

func init() {
    http.Handle("/view", appHandler(listPonies))
}
英文:

There is an blog post on golang.org about error handling that specifically talks about error handling in an AppEngine application. Specifically, check out the "Simplifying repetitive error handling" section.

The way to do error handling is basically to let your handle functions return an error in case they fail and then wrap the call to them with the common error handler:

type appHandler func(http.ResponseWriter, *http.Request) error

func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if err := fn(w, r); err != nil {
        http.Error(w, err.Error(), 500)
    }
}

func listPonies(w http.ResponseWriter, r *http.Request) error {
    ponies, err := ponyService.getAll()

    if err != nil {
        return err;
    }

    w.write(string(ponies))
}

You would also need to register your handlers differently:

func init() {
    http.Handle("/view", appHandler(listPonies))
}

huangapple
  • 本文由 发表于 2014年2月19日 15:20:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/21873631.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定