Mygin之错误恢复Recover中间件
本篇是mygin这个系列的最后一篇。如果想自己动手实现一个类似Gin的Web框架,建议从 mgin第一篇开始,
总代码行数有效行数只有600多行
github源码 mygin
目的
- 实现错误处理机制
panic简介
在实现错误处理机制之前,我们知道在Go 中,错误的处理方式依靠return返回,由调用者处理。如果是不可恢复的错误,可以手动抛出错误,当然在实际运行中,也会遇到不可处理的错误,比如说除数为0的时候painc 也会触发。终止当前的程序。
手动触发错误
//main.go
func main() {
fmt.Println("before ....")
panic("some err message")
fmt.Println("after ....")
}
- shell
~ go run cmd/main.go
before ....
panic: some err message
goroutine 1 [running]:
main.main()
/var/www/gophp/cmd/main.go:12 +0x5f
exit status 2
程序发生错误
func main() {
i := []int{0}
j := 2
fmt.Println(j / i[0])
}
- shell
go run cmd/main.go
panic: runtime error: integer divide by zero
goroutine 1 [running]:
main.main()
/var/www/gophp/cmd/main.go:13 +0x194
exit status 2
painc 的介绍到此为止,也就是发生了painc 错误,对程序来说就是比较严重的,就会中断,但是这个时候需要捕获到这个painc 错误,Go中没有try...Catch...又想捕获错误,这个时候就该defer 出场了。
defer简介
panic会导致程序被中止,但是在程序终止前,会先把当前协程上已经defer的任务,执行完成后再终止。效果类似于其他语言的try...catch。
示例
//cmd/main.go
func main() {
defer func() {
fmt.Println("defer....")
}()
i := []int{0}
j := 2
fmt.Println(j / i[0])
}
- shell
~ go run cmd/main.go
defer....
panic: runtime error: integer divide by zero
goroutine 1 [running]:
main.main()
/var/www/gophp/cmd/main.go:16 +0x1d3
exit status 2
可以看到,在程序退出之前先执行了defer 中的函数。如果能在defer 中捕获painc 错误,那么就能实现其他语言的try...catch
recover函数
介绍之前看官方文档怎么定义的
// The recover built-in function allows a program to manage behavior of a
// panicking goroutine. Executing a call to recover inside a deferred
// function (but not any function called by it) stops the panicking sequence
// by restoring normal execution and retrieves the error value passed to the
// call of panic. If recover is called outside the deferred function it will
// not stop a panicking sequence. In this case, or when the goroutine is not
// panicking, or if the argument supplied to panic was nil, recover returns
// nil. Thus the return value from recover reports whether the goroutine is
// panicking.
翻译后...
recover 内置函数允许程序管理恐慌的 goroutine 的行为。在延迟函数(但不是它调用的任何函数)
中执行恢复调用会通过恢复正常执行来停止 panic 序列,并检索传递给 panic 调用的错误值。如果
在延迟函数之外调用 recover,则不会停止紧急序列。在这种情况下,或者当 goroutine 没有
panic 时,或者如果提供给 panic 的参数为 nil,则 recover 返回 nil。因此,recover 的
返回值报告 goroutine 是否处于恐慌状态。
应用
- cmd/main.go
func main() {
defer func() {
fmt.Println("defer....")
if err := recover(); err != nil {
fmt.Printf("recover 到错误信息:%s\n", err.(error).Error())
fmt.Println("recover success")
}
}()
i := []int{0}
j := 2
fmt.Println(j / i[0])
fmt.Println("after panic")
- shell
~ go run cmd/main.go
defer....
recover 到错误信息:runtime error: integer divide by zero
recover success
可以看到已经捕获到错误信息了,程序正常结束。 after panic 没有打印,这是正确的,当panic 被触发时,程序的执行栈就到定义的defer 函数。就像在try代码块中发生了异常,执行栈来到 catch,接下来执行 catch 代码块中的代码。而在 main() 中打印了 recover success,说明程序已经恢复正常,继续往下执行直到结束。
mygin的错误处理
对一个 Web 框架而言,错误处理机制是必要的。如果发生了painc错误,应当返回错误信息或告诉对方失败了,而不至于什么都不返回,对调用方十分不友好。
例如我有如下的逻辑
package main
import (
"fmt"
"github.com/scott-pb/mygin"
"net/http"
"strconv"
)
func main() {
r := mygin.Default()
group := r.Group("/api")
group.GET("/recovery/:index", func(c *mygin.Context) {
index := c.Params.ByName("index")
i, _ := strconv.ParseInt(index, 10, 10)
s := []int{1, 3, 5, 7, 9}
c.String(http.StatusOK, fmt.Sprintf("index:%d result:%d success!\n", i, s[i]))
})
err := r.Run(":8088")
if err != nil {
fmt.Println(err)
}
}
根据调用方传递的index下标函数数组中的值,当传递的index超过数组下标时,就会发生painc错误,如果执行/api/recovery/10 时,就会发生错误。调用方什么返回都没有。
这个时候,就需要添加一个错误的处理机制,当错误发生时,向调用方返回Internal Server Error,且打印必要的错误信息,方便进行错误定位。
实现中间件 Recovery
新增文件 gee/recovery.go,在这个文件中实现中间件 Recovery
package mygin
import (
"fmt"
"net/http"
)
// Recovery 发生错误时,恢复函数,且返回相应错误信息。
func Recovery() HandlerFunc {
return func(c *Context) {
// 使用defer延迟执行,以便在函数退出时进行recover
defer func() {
if err := recover(); err != nil {
// 如果发生panic,打印错误信息并返回500 Internal Server Error响应
fmt.Println(err.(error).Error())
c.Writer.Write([]byte("Internal Server Error\n"))
c.status = http.StatusInternalServerError
c.Abort() // 终止后续中间件的执行
}
}()
c.Next() // 调用下一个中间件或处理函数
}
}
Recovery 方法很简单,使用defer挂载上错误恢复的函数,在这个函数中调用 recover方法,捕获panic,打印错误信息,并且向调用方返回 Internal Server Error。
// Default 返回一个默认的引擎实例
func Default() *Engine {
engine := New()
//Logger Recovery 中间件
engine.Use(Logger(), Recovery())
// Group 保存 engine 的指针
engine.RouterGroup.engine = engine
return engine
}
接下来就是测试了
测试
- shell
~ curl http://127.0.0.1:8088/api/recovery/1
index:1 result:3 success!
~ curl http://127.0.0.1:8088/api/recovery/10
Internal Server Error
- 控制台输出
可以看到第一次请求返回200成功,第二次请求,先打印了错误信息,然后对应的返回500错误,且调用方接收到了Internal Server Error。
Mygin之错误恢复Recover中间件的更多相关文章
- Go语言 异常panic和恢复recover用法
Go语言 异常panic和恢复recover用法 背景:Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在 ...
- Android IOS WebRTC 音视频开发总结(七五)-- WebRTC视频通信中的错误恢复机制
本文主要介绍WebRTC视频通信中的错误恢复机制(我们翻译和整理的,译者:jiangpeng),最早发表在[这里] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:blac ...
- webrtc如何进行错误恢复
视频的压缩方法:(三种帧) 为了视频尽可能的保持高效,视频数据通过不同的编码进行压缩.以帧为单位进行压缩,按照压缩中的不同作用可分类为:内帧(Intra-frames,I帧),预测帧(Predicti ...
- linux dd实现磁盘完整全盘镜像备份backup,恢复recover(restore)
1,dd操作就是简单的按字节复制,什么分区表啊,MBR(master boot record)啊统统照搬; 1. 磁盘克隆 也就是把整个硬盘复制一份.当然你首先需要在计算机上在接上一块新硬盘,并让系统 ...
- 禁用 Windows 启动时错误恢复的“启动启动修复(推荐)”
bcdedit /set {default} bootstatuspolicy ignoreallfailures bcdedit /set {current} recoveryenabled No
- StatusCodePagesMiddleware中间件如何针对响应码呈现错误页面
StatusCodePagesMiddleware中间件如何针对响应码呈现错误页面 StatusCodePagesMiddleware中间件与ExceptionHandlerMiddleware中间件 ...
- ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”
ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面” DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求 ...
- .Net Core中间件和过滤器实现错误日志记录
1.中间件的概念 ASP.NET Core的处理流程是一个管道,中间件是组装到应用程序管道中用来处理请求和响应的组件. 每个中间件可以: 选择是否将请求传递给管道中的下一个组件. 可以在调用管道中的下 ...
- 【原创】express3.4.8源码解析之中间件
前言 注意:旧文章转成markdown格式. 中间件(middleware)的概念来自于TJ的connect库,express就是建立在connect之上. 就如同connect的意思是 连接 一样, ...
- Oracle RMAN备份恢复指导书
目 录 1 目的与范围... 1 2 术语和定义... 1 3 角色和职责... 2 4 使用RMAN备份数据库... 2 4.1.1 检查数据库模式... 2 4.1.2 连接到target数据库. ...
随机推荐
- 11、SpringBoot-mybatis-plus-druid多源数据事务
系列导航 springBoot项目打jar包 1.springboot工程新建(单模块) 2.springboot创建多模块工程 3.springboot连接数据库 4.SpringBoot连接数据库 ...
- 【驱动】SPI驱动分析(二)-SPI驱动框架
SPI驱动框架 SPI驱动属于总线-设备-驱动模型的,与I2C总线设备驱动模型相比,大体框架是一样,他们都是实际的总线.总体框架如下图所示: 从上到下,分为三层,用户空间,内核空间,和硬件层. 用户空 ...
- P5731
https://www.luogu.com.cn/problem/P5731 这道题被标为红题,真实难度应该介于红题和橙题之间,问题在于我高估了它的难度,以为至少有橙题的难度,一般不打表的我毫不犹豫选 ...
- C#爬虫知识介绍
爬虫 爬虫(Web Crawler)是指使用程序自动获取互联网上的信息和数据的一种技术手段.它通常从一个起始网址出发,按照一定的规则递归地遍历网页,并将有用的信息提取出来,然后存储到本地或者数据库中, ...
- C#格式化输入数据为货币格式
private void btn_Get_Click(object sender, EventArgs e) { double P_dbl_value;//定义double类型变量 if (doubl ...
- zookeeper 集群环境搭建及集群选举及数据同步机制
本文为博主原创,未经允许不得转载: 目录: 1. 分别创建3个data目录用于存储各节点数据 2. 编写myid文件 3. 编写配置文件 4.分别启动 5.分别查看状态 6. 检查集群复制情况 ...
- css - 隐藏body滚动条
body::-webkit-scrollbar{ display: none; }
- [转帖]15--k8s之安全认证
https://www.cnblogs.com/caodan01/p/15137987.html 目录 一.访问控制概述 二.认证管理 三.授权管理 虽然authorization-clusterro ...
- [转帖]如何使用coredump
一.coredump 当用户态进程出现异常后,在该进程的执行目录下生成对应的coredump文件,如果我们想将coredump生成的位置做改变,就需要如下设置. echo "/home/co ...
- [转帖]tgz 安装clickhouse
一.什么是clickhouse ClickHouse是开源的列式存储数据库(DBMS),主要用于在线处理查询(OLAP),能够使用SQL查询实时生成数据分析报告. 下面介绍下安装clickhouse. ...