教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 defer recover保护gin不panic

defer recover保护gin不panic

发布时间:2022-12-28   编辑:jiaochengji.com
教程集为您提供defer recover保护gin不panic等资源,欢迎您收藏本站,我们将为您提供最新的defer recover保护gin不panic资源

本文首发于我的Github博客

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

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

情景

在我们用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

协程解决方案

所以,对于协程,我们要手动进行deferrecover,来避免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的函数

到此这篇关于“defer recover保护gin不panic”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Go 异常处理机制——defer, error, panic, recover
golang panic和recover 实现原理
golang异常处理机制
『GoLang』错误处理
recover 没有捕获异常_GO语言异常处理机制panic和recover分析
Go 学习之路:异常处理defer,panic,recover
golang中的defer recover panic
[翻译]Go的Defer、Panic和Recover
Golang - 访问数据库报错后程序继续运行
golang中的defer panic recover

[关闭]
~ ~