最近写go,路由选择httprouter,现在希望在不修改httprouter源码的前提下,对所有注册的路由handle进行异常捕获。

golang使用panic()产生异常,然后可以recover()来捕获到异常,否则主程序直接宕掉,这是我们不希望看到的。

或者全程检查error,不主动抛出异常。即便这样,可能异常依然不能避免。

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,将业务上代码包裹起来。

golang同理:

func RegRouters(r *httprouter.Router) {
r.GET("/", WrapHandle(Home))
r.GET("/contact", WrapHandle(Contact))
}

WrapHandle需要有一个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
} //更多扩展....

好了,先到这里,希望对你有帮助。

【Golang】如何统一处理HTTP请求中的异常捕获的更多相关文章

  1. Swoole 中协程的使用注意事项及协程中的异常捕获

    协程使用注意事项 协程内部禁止使用全局变量,以免发生数据错乱: 协程使用 use 关键字引入外部变量到当前作用域禁止使用引用,以免发生数据错乱: 不能使用类静态变量 Class::$array / 全 ...

  2. 02 flask 请求钩子、异常捕获、上下文、Flask-Script 扩展、jinja2 模板引擎、csrf防范

    一 请求勾子 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如: 在请求开始时,建立数据库连接: 在请求开始时,根据需求进行权限校验: 在请求结束时,指定数据的交互格式: 为了让每个 ...

  3. [日常] 使用TCPDUMP和Ethereal抓包分析HTTP请求中的异常情况

    在测试功能的过程中,出现这样一种现象.前端js发起ajax请求后,在浏览器的审查元素网络状态中可以看到status为pending,等15秒以后js会把当前超时的请求取消掉,变成了红色的cancel. ...

  4. JAVA 线程中的异常捕获

    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked e ...

  5. C#中的异常捕获机制(try catch finally)

    (转自:http://blog.csdn.net/zevin/article/details/6901489) 一.C#的异常处理所用到关键字try 用于检查发生的异常,并帮助发送任何可能的异常.ca ...

  6. python中的异常捕获怎么用?

    http://www.2cto.com/kf/201301/184121.html http://www.w3cschool.cc/python/python-exceptions.html try: ...

  7. AngularJS 用 Interceptors 来统一处理 HTTP 请求和响应

    Web 开发中,除了数据操作之外,最频繁的就是发起和处理各种 HTTP 请求了,加上 HTTP 请求又是异步的,如果在每个请求中来单独捕获各种常规错误,处理各类自定义错误,那将会有大量的功能类似的代码 ...

  8. 使用domain模块捕获异步回调中的异常

    和其他服务器端语言相比,貌似node.js 对于异常捕捉确实非常困难. 首先你会想到try/catch ,但是在使用过程中我们会发现并没有真正将错误控制在try/catch 语句中. 为什么? 答案是 ...

  9. node.js 使用domain模块捕获异步回调中的异常

    和其他服务器端语言相比,貌似node.js 对于异常捕捉确实非常困难. 首先你会想到try/catch ,但是在使用过程中我们会发现并没有真正将错误控制在try/catch 语句中. 为什么? 答案是 ...

随机推荐

  1. C#解析JSON字符串总结(转载)

    JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...

  2. C++指针和字符串

    ]="rose'; cout<<flowers<<endl; 数组名是第一个元素的地址,

  3. 区间修改区间求和cdq分治

    https://www.luogu.org/problemnew/show/P3372 #include<bits/stdc++.h> #define fi first #define s ...

  4. VS2019正式版注册码秘钥

    Visual Studio 2019 EnterpriseBF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 ProfessionalNYWVH-HT4X ...

  5. Linux - Ubuntu 图形界面入门

    Ubuntu 图形界面入门 目标 熟悉 Ubuntu 图形界面的基本使用 01. Ubuntu 的任务栏 02. 窗口操作按钮 03. 窗口菜单条 ——本文源自<黑马程序员>

  6. LayUI左侧菜单无法保持选中状态

    1.问题描述:一般的左侧菜单都会是动态添加的模块,利用循环把模块名和链接地址逐个显示出来如下图 但是问题来了,只要点任何二级菜单就不会保持左侧菜单当前一级菜单和二级菜单选中状态. 2.分析原因:因为模 ...

  7. BigDecimal 类型转换、运算、比较

    序:Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数 ...

  8. blender基础操作

    旋转:鼠标中键 左右移动:鼠标中键+左shift 放大缩小:鼠标滚轮滚动 blender旋转以锁定物件作为中心点旋转 blender选取物件用鼠标右键, 选中物件之后,利用数字键盘中的点(Del) 来 ...

  9. Swift Realm 完整使用记录

    新项目用到了数据库,本来之前用的都是 SQL,但是语法写的实在是恶心,所以使用 Realm 尝试一下. 1.我使用的 pod 库,所以先 pod 库安装一下,安装完别忘了先编译一下,不然 import ...

  10. JavaSE基础知识(5)—面向对象(对象数组和对象关联)

    一.对象数组 1.说明 数组的定义类型为对象类型 2.动态初始化 1.声明并开辟空间 Person[] pers = new Person[长度];2.赋值 for(int i=0;i<pers ...