"Go Framework" How does the gin framework handle panic?

In this article, we introduce the application of recover in the gin framework. First of all, in golang, if panic is encountered in the sub-coroutine, the main coroutine will also be terminated. as follows:

package main

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

func main() {
    
    
	r := gin.Default()

    // 在子协程中引起panic,主协程也会退出
	go func() {
    
    
		panic("hello world")
	}()
    
	// Listen and Server in 0.0.0.0:8080
	r.Run(":8080")
}


Panic is described as an error that cannot be handled. In web services, the service will crash. Of course, this is unacceptable in a production environment. So, how can we capture the panic when a panic occurs and allow the service to continue to run healthily?
This is the recover function provided in golang. The recover function can capture Panic errors and restore the normal operation of the program.
Next, let's take a look at how the recover function is applied in the gin framework.
First of all, what I want to mention is the recovery middleware in the gin framework. In gin, this middleware is used to capture panic and ensure that the service does not go down. If you use the gin.Default() function to build a gin object, the Recovery middleware is registered by default.

func Default() *Engine {
    
    
	debugPrintWARNINGDefault()
	engine := New()
    //  注册了Recovery中间件
	engine.Use(Logger(), Recovery())
	return engine
}

Secondly, let's take a look at what the Recovery() middleware does.

The Recovery() function is defined as follows:

func Recovery() HandlerFunc {
    
    
	return RecoveryWithWriter(DefaultErrorWriter)
}

The DefaultErrorWriter here is the default output port, which is os.Stderr. That is, where the error is output.

Next, look at the implementation in the RecoveryWithWriter function

// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.
func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc {
    
    
	if len(recovery) > 0 {
    
    
		return CustomRecoveryWithWriter(out, recovery[0])
	}
	return CustomRecoveryWithWriter(out, defaultHandleRecovery)
}

There is a parameter here called defaultHandleRecovery. Let’s take a look at its implementation:

func defaultHandleRecovery(c *Context, err any) {
    
    
	c.AbortWithStatus(http.StatusInternalServerError)
}

It writes a status code 500 representing an internal server error and ends the request.

The key point here is the implementation of CustomRecoveryWithWriter. The code is very long, so let’s look at it in sections. As follows:
Insert image description here
Mainly divided into three parts:

Output the log to out. Here is the DefaultErrorWriter mentioned above, which is os.Stderr.
defer delayed execution part.
c.Next() normal request processor part.

The points to note here are:

The recover function needs to be called in defer. Because defer is called when the function returns, it will cause the function to return when a panic occurs, so that the panic can be captured.
Running as middleware means that each request processor is wrapped by middleware, which is equivalent to each request processor having this defer function.
In the defer function, if the panic is captured, the details of the panic will be recorded in detail and can be sent to the specified output, that is, the out parameter specified in the function (the default is os.Stderr), or other files or Sentry can be specified. wait.

In gin, it is the application of this middleware that ensures the robustness of web services. Of course, other web frameworks also have the same mechanism, and the implementation principles are the same.

Guess you like

Origin blog.csdn.net/m0_73728511/article/details/133325772