Gin Framework – Part 2

Start the service

// Gin service startup code

package main

// Introduce gin framework
import "github.com/gin-gonic/gin"

func main() {
	// Create a default routing engine
	engine := gin.Default()
	// Register Get route
	engine.GET("/", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"msg": "request succeeded",
		})
	})
	// The default listener is 0.0.0.0:9090
	_ = engine.Run(":9090")
}

Start output

$ go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :9090

Code Analysis

Analysis of Gin service startup code.

import “github.com/gin-gonic/gin”

When you initiate the Gin framework, the related init() methods in the package will be executed; the following two init methods are found:

a. The first init method

package gin
func init() {
  // Set up AppEngine = true
	defaultAppEngine = true
}

b. The second init method

func init() {
  // Set the running mode of the service, the default is DebugMode
  // There are three modes: DebugMode=0 (development mode), releaseCode=1 (production mode), testCode=2 (test mode)
	mode := os.Getenv(EnvGinMode)
	SetMode(mode)
}

gin.Default()

The source code of gin.Default is as follows:

func Default() *Engine {
  // print gin-debug information
	debugPrintWARNINGDefault()
  // Create a new engine with no routing and no intermediate
	engine := New()
  // Register global logging and exception catch middleware
	engine.Use(Logger(), Recovery())
	return engine
}

Middleware is registered in the Gin framework through engine.

engine.GET(“/”,…)

// Register a Get request route with a matching path (relativePath)
// handlers is the corresponding processing logic
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
	return group.handle(http.MethodGet, relativePath, handlers)
}

"/" In the above example code, we registered a route that matches the root directory ( ), the processing handlers is an anonymous function, and the data in the ctx.JSON returned json format is called directly.

// Register Get route
engine.GET("/", func(ctx *gin.Context) {
  ctx.JSON(200,gin.H{
    "msg":"request succeeded",
  })
})

Multiple return formats

In the gin.Context support of multiple return formats, the commonly used return formats are as follows:

Method Name Describe
ctx.XML(code int, obj interface{}) return xml
ctx.AsciiJSON(code int, obj interface{}) return json, will encode special characters
ctx.PureJSON(code int, obj interface{}) returns json, and html some are not escaped.

Comparison of Json, AsciiJSON, PureJSON

package main

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

func main() {
	// Create a default routing engine
	engine := gin.Default()
	// Register Get route
	engine.GET("/", func(ctx *gin.Context) {
		key, _ := ctx.GetQuery("key")
		msgBody := gin.H{
			"msg":  "request succeeded",
			"html": "<span>🤖: I am a piece of html code!</span>",
		}
		switch key {
		case "1":
			msgBody["method"] = "ctx.JSON"
			ctx.JSON(200, msgBody)
		case "2":
			msgBody["method"] = "ctx.PureJSON"
			ctx.PureJSON(200, msgBody)
		case "3":
			msgBody["method"] = "ctx.AsciiJSON"
			ctx.AsciiJSON(200, msgBody)
		default:
			ctx.JSON(500, gin.H{
				"msg": "request failed",
			})
		}
		return
	})
    // The default listener is 0.0.0.0:9090
	_ = engine.Run(":9090")
}

The request returns:

$ curl http://127.0.0.1:9090/\?key\=1
{"html":"\u003cspan\u003e🤖: I am a piece of html code!\u003c/span\u003e","method":"ctx.JSON","msg":"request succeeded"}%

$ curl http://127.0.0.1:9090/\?key\=2
{"html":"<span>🤖: I am a piece of html code!</span>","method":"ctx.PureJSON","msg":"request succeeded"}

$ curl http://127.0.0.1:9090/\?key\=3
{"html":"\u003cspan\u003e\u1f916: I am a piece of html code!\u003c/span\u003e","method":"ctx.AsciiJSON","msg":"request succeeded"}%

Summarize

Method Phenomenon
ctx.JSON By default, html will be converted into unicode characters, and no additional processing will be performed on special characters.
ctx.PureJSON html returned as it is, and no additional processing will be done to special characters.
ctx.AsciiJSON Special characters and html processed together.

engine.Run()

The source code is as follows

func (engine *Engine) Run(addr ...string) (err error) {
	// Delay close the output of ERROR type log information
	defer func() { debugPrintError(err) }()
	// Set CIDR (Typeless Inter-Domain Routing) information, default return: 0.0.0.0/0
	trustedCIDRs, err := engine.prepareTrustedCIDRs()
	if err != nil {
		return err
	}
	engine.trustedCIDRs = trustedCIDRs
	// Set the listening IP and port information, the default is ":9090"
	address := resolveAddress(addr)
	debugPrint("Listening and serving HTTP on %s\n", address)
	// Start the service
	err = http.ListenAndServe(address, engine)
	return
}

Why the default monitor is “:9090”

Run Called in resolveAddress(addr) the method, the source code of the method is as follows:

// Receives a string slice parameter
func resolveAddress(addr []string) string {
  // If the parameter length is 0, the default listening 9090
	switch len(addr) {
	case 0:
		if port := os.Getenv("PORT"); port != "" {
			debugPrint("Environment variable PORT=\"%s\"", port)
			return ":" + port
		}
		debugPrint("Environment variable PORT is undefined. Using port :9090 by default")
		return ":9090"
	case 1:
      // If the parameter length is 1, listen on IP and port
		return addr[0]
	default:
     //  If the parameter length is greater than 1, an error will be reported
		panic("too many parameters")
	}
}