defer+recover保护gin不panic

Go panic/recover机制深度解析与生产防护实践 panic是Go语言中程序不可恢复崩溃的运行时信号,其本质并非错误处理而是goroutine级的紧急终止机制;recover并非异常捕获,而是在defer链中对panic传播的精准拦截;defer则构成panic传播路径上唯一的可控拦截点。理解三者协同关系,是构建高可用Go服务的基础能力。该机制支撑了HTTP中间件全局兜底、数据库操作安全封装、并发goroutine隔离等关键工程实践,广泛应用于微服务、支付网关、消息队列等对稳定性要求严苛的生产场景。 阅读详情

本文首发于我的Github博客

本文记录了作者保护gin构建的web app不panic的方式,简单来说:

  1. 主程中的panic本身是会被gin拦截的
  2. 协程中的panic需要使用defer和recover进行保护

情景

在我们用gin构建,运行web app并上线了之后,或许有一些请求会经过业务,在特定的情况下出发会触发golang中的panic

按照golang的设定,一旦panic,如果不在函数调用栈中存在recover,那么是一定会使得整个程序终止的

但是线上的服务是不能够因为一个两个的请求就直接终止了的,这样非常危险,所以我们需要手段来阻止web app在panic的情况下直接终止

解决方案

主程序中的panic

对于gin这个web框架来说,主程序中的panic是会被自动recover的,还会打印出非常详细的日志信息,比如

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/panic", func(ctx *gin.Context) {
        panic("panic")
    })
    r.Run()
}

运行之后我们作如下HTTP请求

> curl localhost:8080/panic

会发现在gin的运行窗口出现如下信息

2020/06/04 18:42:12 [Recovery] 2020/06/04 - 18:42:12 panic recovered:
GET /panic HTTP/1.1
Host: localhost:8080
Accept: */*
User-Agent: curl/7.64.1


panic
/Users/admin/go/src/gin-test/main.go:10 (0x1581418)
        main.func1: panic("panic")
/Users/admin/go/src/github.com/gin-gonic/gin/context.go:165 (0x156baca)
        (*Context).Next: c.handlers[c.index](c)
/Users/admin/go/src/github.com/gin-gonic/gin/recovery.go:83 (0x157fb13)
        RecoveryWithWriter.func1: c.Next()
/Users/admin/go/src/github.com/gin-gonic/gin/context.go:165 (0x156baca)
        (*Context).Next: c.handlers[c.index](c)
/Users/admin/go/src/github.com/gin-gonic/gin/logger.go:241 (0x157ec40)
        LoggerWithConfig.func1: c.Next()
/Users/admin/go/src/github.com/gin-gonic/gin/context.go:165 (0x156baca)
        (*Context).Next: c.handlers[c.index](c)
/Users/admin/go/src/github.com/gin-gonic/gin/gin.go:420 (0x1575d20)
        (*Engine).handleHTTPRequest: c.Next()
/Users/admin/go/src/github.com/gin-gonic/gin/gin.go:376 (0x157548c)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/Cellar/go/1.13.8/libexec/src/net/http/server.go:2802 (0x12cb6d3)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/Cellar/go/1.13.8/libexec/src/net/http/server.go:1890 (0x12c6f74)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/Cellar/go/1.13.8/libexec/src/runtime/asm_amd64.s:1357 (0x105c030)
        goexit: BYTE    $0x90   // NOP

[GIN] 2020/06/04 - 18:42:12 | 500 |    1.238546ms |             ::1 | GET      "/panic"

并且整个app还在正常运行,没有终止,这非常好

协程中的panic

不过非常可惜的是,对于协程中的panic,gin并不能做到自动recover并打印日志信息,比如

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/go-panic", func(ctx *gin.Context) {
        go func() {
            panic("panic")
        }()
    })
    r.Run()
}

运行该app之后,我们作如下的HTTP请求

> curl localhost:8080/go-panic

会发现gin app退出了

panic: panic

goroutine 24 [running]:
main.main.func1.1()
        /Users/admin/go/src/gin-test/main.go:11 +0x39
created by main.main.func1
        /Users/admin/go/src/gin-test/main.go:10 +0x35
exit status 2
协程解决方案

所以,对于协程,我们要手动进行defer和recover,来避免app的退出和打印日志信息,比如上面的代码应该修改为

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/go-panic", func(ctx *gin.Context) {
        go func() {
            defer func() {
                if err := recover(); err != nil {
                    fmt.Printf("error: %v\n", err)
                }
            }()
            panic("panic")
        }()
    })
    r.Run()
}

而后我们像刚才一样进行HTTP请求

> curl localhost:8080/go-panic

会得到如下打印

error: panic
[GIN] 2020/06/04 - 18:50:20 | 200 |       2.951µs |             ::1 | GET      "/go-panic"

可以看到app正常响应了请求,并且没有退出并打印了日志,想要更多定制操作可以修改defer的函数

Go语言核心特性:指针、init函数、闭包与defer详解 指针作为编程语言中的基础概念,通过直接操作内存地址实现高效数据访问。Go语言在保留指针强大功能的同时,通过类型安全、自动内存管理等机制降低了使用风险。理解指针原理有助于优化大对象传递、实现接口方法等场景。init函数是Go特有的初始化机制,通过严格的执行顺序保证程序正确启动。闭包将函数与引用环境结合,在中间件、资源管理等场景表现优异。defer语句以FILO顺序执行延迟调用,是资源清理的理想选择。本文深入解析这些Go核心特性,结合内存逃逸分析、并发安全等工程实践,帮助开发者规避常见陷阱,提升代码质量与性能。 阅读详情

相关推荐

Go函数定义与调用:从签名契约到栈帧执行的底层解析

函数是编程语言最基础的抽象单元,其本质是具备明确输入输出、可复用、可组合的代码块。在Go中,函数设计严格遵循类型安全、显式声明和编译期绑定原则,核心体现为不可变签名、无重载机制及接收者语义。这种设计带来零运行时开销、高并发安全性和强IDE支持等技术价值,广泛应用于HTTP Handler、微服务gRPC接口、并发任务调度等工程场景。理解函数在内存中的栈帧布局、参数传递方式(值拷贝 vs 指针)、返回值生命周期及defer/panic/goroutine协同机制,是写出高性能、低bug Go代码的关键前提——

chunqingtai2922的博客 349

7. Gin中间件-Panic处理

Gin中间件Panic处理

菜鸟的博客 1530

Go函数设计:从语法糖到生产级契约的深度解析

Go函数远不止是基础语法结构,而是运行时数据流、错误传播与资源管理的核心契约机制。其命名返回值、参数传递语义(如string/slice零拷贝)、defer绑定时机等特性,深刻影响内存分配、GC压力与并发安全性。在高并发微服务场景中,不当的函数签名(如大结构体传值、error处理缺失、指针逃逸)直接导致性能瓶颈与panic频发。本文结合opencode go实践与go并发编程真实案例,系统拆解函数定义、参数传递、返回值设计及main生命周期管理等关键链路,为已具备Go开发经验的工程师提供可落地的稳定性优化路

weixin_34090562的博客 399

「Go框架」gin框架是如何处理panic的?

在gin中,是通过使用该中间件来捕获panic,并保证服务不down机的。在defer函数中,如果捕获了panic,则将panic的详细详细记录下来,可以发送到指定的输出中,即函数中指定的out参数(默认是os.Stderr),也可以指定其他的文件或Sentry等。当然,这在生产环境下是不可接受的。首先,在golang中,如果在子协程中遇到了panic,那么主协程也会被终止。在gin中,正是该中间件的应用,确保了web服务的健壮性。当然,其他的web框架也有同样的机制,实现原理也是一样的。

ldxxxxll的博客 847

Go指针原理与nil安全实践:从内存模型到GC优化

指针是编程语言中管理内存和共享数据的基础机制,其核心在于地址获取、类型绑定与安全解引用。Go指针摒弃了C风格的指针算术和强制转换,采用显式可控、隐式安全的设计哲学,使编译器能精确执行逃逸分析,并为垃圾回收器提供可预测的标记路径。这种设计直接支撑了Go GC毫秒级STW(Stop-The-World)的低延迟特性,也决定了nil在Go中是合法零值而非错误标志。在Web服务(如http.ListenAndServeTLS)、并发编程(sync.Pool)、序列化(json.Unmarshal)等典型场景中,正确

weixin_30924239的博客 329

Go错误增强:为error添加结构化上下文与可追溯性

在Go语言中,原生error接口缺乏上下文信息,导致生产环境故障定位困难。其核心原理在于error包装机制(如%w动词)仅支持单向Unwrap,易造成语义丢失与链路断层;而errors.Is/As依赖Unwrap递归遍历,存在性能与深度风险。技术价值体现在提升错误可追溯性、支持结构化日志与精准监控告警。典型应用场景包括HTTP微服务错误透传、数据库操作参数快照、Gin框架集成及panic捕获增强。本文聚焦Go工程化落地中的真实痛点,提供轻量自研ContextError方案,兼顾类型安全、字段可提取与零反射开

hqmln的博客 1964

gin恢复中间件的作用&源码解释

Gin 的恢复中间件(Recovery Middleware)的作用是确保在处理 HTTP 请求时,应用程序不会因为某个处理函数中的 panic(运行时恐慌)而崩溃。相反,中间件会捕获 panic,记录错误信息,并返回一个合适的 HTTP 响应。

weixin_63860405的博客 657

Go中间件模式:洋葱模型与责任链

中间件模式用函数包装handler,在业务逻辑前后插入公共逻辑。洋葱模型的前处理按注册顺序执行,后处理逆序执行。recover放最外层捕获所有异常,auth放在限流前面防止未授权请求消耗限流配额。gin用c.Next()和c.Abort()控制执行流,context在中间件间传递数据。下一篇我们聊工厂模式,看看怎么用map注册创建不同类型的对象。

白话机器学习 89

gin.recovery,gin.default,gin.new浅解

gin.Recovery()/gin.Default()/gin.New()

qq_34252060的博客 2216

阿里平头哥与华为芯片的比较

阿里平头哥与华为芯片代表了中国AI芯片领域的两种典型发展路径:平头哥通过兼容CUDA生态快速切入市场,以较低成本提供接近国际水平的AI算力;华为则坚持全栈自研路线,构建从芯片到框架的完整技术体系,更注重供应链安全和自主可控。从短期来看,平头哥PPU在单卡性能参数上全面超越昇腾910B,接近英伟达H20水平,且成本优势明显,有望在云服务和互联网应用领域取得更大市场份额。而华为昇腾则凭借全栈自研和端边云协同优势,在政企市场和科研领域更具竞争力。

shao.bing的专栏 3981

RAD Studio 12安装全攻略:从下载到破解InterBase的完整流程(附KeyPatch使用技巧)

本文提供RAD Studio 12的完整安装指南,包括系统要求、安装步骤及InterBase数据库的高效配置方法。详细介绍了如何使用KeyPatch工具进行许可证处理,并分享了IDE优化和开发技巧,帮助开发者快速上手这一强大的跨平台开发工具。

q6r7s8t9的博客 948

Go panic不是异常处理,而是程序崩溃时的急救开关

panic是Go语言中用于应对不可恢复致命错误的运行时机制,其本质不同于传统异常处理,而更接近操作系统级的‘内核恐慌’;它基于栈展开与goroutine终止原理,代价高昂且不可跨协程捕获;技术价值在于保障系统状态可信性与快速失败(Fail Fast),适用于初始化校验、不变量断言等场景;在HTTP中间件、Worker Pool任务调度、服务启动配置验证等工程实践中,需严格区分panic与error的职责边界,避免滥用recover掩盖真实问题;本文深入解析panic的真实定位、recover的认知陷阱及分层

WGH100817的博客 404

PHP版本对接支付宝支付接口 电脑网站 详细介绍 沙箱环境 超简单易懂

PHP版本对接支付宝支付接口 其实理顺了思路后,按照我接下来的步骤来,真的超级简单啊,为啥有那么多的朋友们折腾了那么久呢,嘿嘿,跟我走吧~ 我是昨天晚上洗完澡之后,大概八九点,才开始正式开工尝试去这一工程的,我去支付宝的蚂蚁金服开放平台里把各个知识点和文档大概都看了一遍,大致弄明白了要怎么操作了,建议大家看看电脑网站开发文档,忙到了夜里十二点左右,成功地用支付宝给的Demo完成了付款操...

爱玲姐姐的博客 1万+

recover 没有捕获异常_[系列] goginapi 路由中间件 捕获异常(四)

概述首先同步下项目概况:上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常。当系统发生异常时,提示 “系统异常,请联系管理员!”,并发送panic告警邮件。什么是异常?在 Go 中异常就是 panic,它是在程序运行的时候抛出的,当 panic 抛出之后,如果在程序里没有添加任何保护措施的话,控制台就会在打印出 panic 的详细情况,然后终止运行。...

weixin_29281915的博客 218

从零开始STM32cubeide学习

使用的是正点原子的精英版,单片机是STM32F103ZET6,详细讲解完成跑马灯实验

weixin_44077208的博客 2279

【AI学习笔记】Coze平台实现将Excel文档批量导入数据库全过程

通过Coze平台实现将Excel文档批量导入数据库的全流程,包括B站现有参考教程全方位解读、自己实操的一些BUG解决过程,以及一些疑难问题的探索。

bailichen800的博客 8825

c++ 未捕获的异常_Gin 框架系列 — 路由中间件 捕获异常

概述首先同步下项目概况:上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常。当系统发生异常时,提示 “系统异常,请联系管理员!”,并发送panic告警邮件。什么是异常?在 Go 中异常就是 panic,它是在程序运行的时候抛出的,当 panic 抛出之后,如果在程序里没有添加任何保护措施的话,控制台就会在打印出 panic 的详细情况,然后终止运行。...

weixin_33747775的博客 383

Java 大视界 -- Java+Spark MLlib 构建智能推荐系统:协同过滤算法实战与优化(441)

Java+Spark MLlib构建智能推荐系统实战 本文详细介绍了基于Java和Spark MLlib构建协同过滤推荐系统的全流程实践方案。主要内容包括: 架构设计:采用离线批处理为主、近实时更新为辅的架构,包含数据采集层、处理层、模型层、推荐生成层、存储层和应用层六大模块,可支撑千万级用户推荐需求。 技术实现: 使用Spark MLlib的ALS算法进行协同过滤模型训练 提供数据清洗、模型训练、推荐生成等核心代码实现 采用MySQL存储推荐结果,支持批量插入和事务保障 生产级优化: 版本化模型存储规避覆

【青云交】华为云云享专家 | 阿里云开发者社区专家博主 技术圈个人影响力前 9 | 博客之星 TOP12 优快云 首位四榜(原力榜 / 作者周榜 / 领军人物 / 综合热榜)榜首,破平台纪录! 苏州地区全榜霸榜,感恩全网十多万粉丝同行! 2531

c++ 未捕获的异常_[系列] - go-gin-api 路由中间件 - 捕获异常(四)

概述首先同步下项目概况:上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常。当系统发生异常时,提示 “系统异常,请联系管理员!”,同时并发送 panic 告警邮件。什么是异常?在 Go 中异常就是 panic,它是在程序运行的时候抛出的,当 panic 抛出之后,如果在程序里没有添加任何保护措施的话,控制台就会在打印出 panic 的详细情况,然后终止运行。我们可...

weixin_35890184的博客 92

Keras中神经网络可视化模块keras.utils.visualize_util安装配置方法

Keras中神经网络可视化模块keras.utils.visualize_util安装配置方法

jacke121的专栏 2759

HDMI接口及其在编程中的应用

在编程中,我们可以使用HDMI接口来控制和管理连接到计算机的HDMI设备。本文将介绍HDMI接口的基本原理以及如何在编程中使用HDMI接口。在编程中,我们可以使用HDMI接口来控制和管理连接到计算机的HDMI设备。本文介绍了HDMI接口的基本原理,并提供了使用Python编程语言和相关库实现HDMI接口应用的示例代码。我们可以使用编程语言提供的音频库来生成和播放音频,并将其通过HDMI接口输出到连接的设备上。我们可以使用编程语言提供的音频库来生成和播放音频,并将其通过HDMI接口输出到连接的设备上。

CodeByte的博客 802

[系列] - go-gin-api 路由中间件 - 捕获异常(四)

概述首先同步下项目概况:上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常。当系统发生异常时,提示 “系统异常,请联系管理员!”,并发送...

新亮笔记 2888

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

golang面试题

通道(channel)是 Go 语言用于 goroutine 间通信和同步的工具。就像一个传送带,一端的 goroutine 可以把数据放上去(发送数据),另一端的 goroutine 能从上面取走数据(接收数据),保障数据安全有序传递,避免数据竞争问题。数组:定义时必须明确指定长度,且该长度固定,不可更改。数组长度属于其类型的一部分,不同长度的数组属于不同类型。切片:是对数组的抽象,长度可在运行时动态改变。它本身不存储数据,而是指向一个底层数组。

qq_66313178的博客 1795

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Go错误处理实战:构建可诊断、可分类、可降级的错误流

在Go语言中,错误不是异常而是值,其核心设计哲学是将失败作为显式控制流纳入函数契约。理解error接口的本质、掌握errors.As/errors.Is的语义匹配能力、区分Transient/Business/Fatal错误级别,是实现高可靠服务的基础。本文围绕API调用中常见的'404 not found'、'stream disconnected'等典型错误场景,详解如何通过自定义错误类型(如APIError、NetworkError)、HTTP客户端自动包装、中间件分级重试及结构化日志监控,构建一套可

weixin_34008784的博客 598

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Golang基础面试题汇总

channel、goroutine、slice、map、反射、内存、GC、Musql、Redis、ELK、K8s、Http、Https

weixin_41760738的博客 5696
上一篇: bash中的字符串处理操作
下一篇: 常见的git工作流
FitzLeopard
博客等级 码龄9年 6粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值