【Golang】如何统一处理HTTP请求中的异常捕获
2017-09-21 15:28
555 查看
最近写GOLANG项目,不使用框架,路由选择httprouter
现在想实现一个需求:在不修改httprouter源码的前提下,对所有注册的路由handle进行异常捕获。
大家都知道golang使用panic()产生异常,然后可以recover()来捕获到异常,否则主程序直接宕掉,这是我们不希望看到的。
或者全程检查error,不主动抛出异常。即便这样,可能异常依然不能避免。
既然要recover(),但又不想在每个handle里面都去recover()一遍,如果你也有这样的需求,下面讲到的可能对你有用。
正常的路由表长这样。在C#中相当于对每个请求加try...catch,将业务上代码包裹起来。
可能你已经想到了,对,包裹起来,像这样:
那这个wrap方法长什么样呢?他需要有一个handle类型的参数,同时返回值要能被httprouter接收,直接上代码
是不是很简单~ 我们再改造一下,加一个上下文,把handle简化一下
看出有什么不同了吗?对,多了一个context包,handle的参数也减少到一个,主要是context上可以做更多的事情。
一个简单的请求上下文的原型:
好了,先到这里,希望对你有帮助。
现在想实现一个需求:在不修改httprouter源码的前提下,对所有注册的路由handle进行异常捕获。
大家都知道golang使用panic()产生异常,然后可以recover()来捕获到异常,否则主程序直接宕掉,这是我们不希望看到的。
或者全程检查error,不主动抛出异常。即便这样,可能异常依然不能避免。
既然要recover(),但又不想在每个handle里面都去recover()一遍,如果你也有这样的需求,下面讲到的可能对你有用。
func RegRouters(r *httprouter.Router) { r.GET("/", Home) r.GET("/contact", Contact) } func Home(w http.ResponseWriter, r *http.Request, params httprouter.Params) { defer func() { if pr := recover(); pr != nil { fmt.Printf("panic recover: %v\r\n", pr) debug.PrintStack() } }() //something } func Contact(w http.ResponseWriter, r *http.Request, params httprouter.Params) { defer func() { if pr := recover(); pr != nil { fmt.Printf("panic recover: %v\r\n", pr) debug.PrintStack() } }() //something }
正常的路由表长这样。在C#中相当于对每个请求加try...catch,将业务上代码包裹起来。
可能你已经想到了,对,包裹起来,像这样:
func RegRouters(r *httprouter.Router) { r.GET("/", WrapHandle(Home)) r.GET("/contact", WrapHandle(Contact)) }
那这个wrap方法长什么样呢?他需要有一个handle类型的参数,同时返回值要能被httprouter接收,直接上代码
func WrapHandle(handle httprouter.Handle) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { defer func() { if pr := recover(); pr != nil { fmt.Printf("panic recover: %v\r\n", pr) debug.PrintStack() } }() handle(w, r, p) } }
是不是很简单~ 我们再改造一下,加一个上下文,把handle简化一下
func WrapHandle(handle func(ctx *context.Context)) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { defer func() { if pr := recover(); pr != nil { fmt.Println("panic recover: %v", pr) debug.PrintStack() } }() ctx := context.NewContext(w, r, p) handle(ctx) } } func Home(ctx *context.Context) { defer func() { if pr := recover(); pr != nil { fmt.Printf("panic recover: %v\r\n", pr) debug.PrintStack() } }() //something } func Contact(ctx *context.Context) { defer func() { if pr := recover(); pr != nil { fmt.Printf("panic recover: %v\r\n", pr) debug.PrintStack() } }() //something id = ctx.FormInt64("id") //通过context从FORM取值,并转换为int64 }
看出有什么不同了吗?对,多了一个context包,handle的参数也减少到一个,主要是context上可以做更多的事情。
一个简单的请求上下文的原型:
type Context struct { responseWriter http.ResponseWriter request *http.Request params httprouter.Params Data map[string]interface{} } func NewContext(w http.ResponseWriter, r *http.Request, params httprouter.Params) *Context { ctx := new(Context) ctx.responseWriter = w ctx.request = r ctx.params = params ctx.Data = make(map[string]interface{}) return ctx } func (ctx *Context) FormValue(name string) string { return ctx.request.FormValue(name) } func (ctx *Context) FormInt64(name string) int64 { value, _ := strconv.ParseInt(ctx.FormValue(name), 10, 64) return value } //更多扩展....
好了,先到这里,希望对你有帮助。
相关文章推荐
- 如何捕获和处理逃出线程外的异常
- Android中如何处理未捕获的异常
- HandlerExceptionResolver统一捕获系统异常做处理
- Android如何处理未捕获异常
- C#_WinForm 统一捕获未处理的异常
- C#.NET--如何处理程序的未捕获异常
- java中如果我老是少捕获什么异常,如何处理?
- Winform 统一捕获异常,捕获未处理异常
- 如何判断所捕获的异常类型,并根据其进行优雅处理
- golang web框架 utron 的异常统一处理
- Android如何处理未捕获异常
- ASP.NET MVC 的统一异常处理有多难?(衍生的意图,出错后如何保持表单的状态?)
- Spring boot异常统一处理方法:@ControllerAdvice注解的使用、全局异常捕获、自定义异常捕获
- 在一个网站里有很多aspx页 如何统一处理项目中的所有异常?(面试题)
- Android -- 小功能 如何处理未捕获异常
- 在执行lua脚本时如何统一捕获异常
- C#_WinForm捕获未处理的异常
- 6.2判断一个数能否被3整除,如果不能整除就抛出一个异常,并让其调用方法来捕获,显示相应的处理信息
- c/c++的异常统一处理
- javascript学习笔记(五):异常捕获和事件处理