2020 latest Gin framework Chinese document (updated on 2020.06) regular maintenance

2020 latest Gin framework Chinese document (updated on 2020.06) regular maintenance

##  
	 asong Gin 
	 
	 
	 
	 
	 
	 
	github:https://github.com/sunsong2020/Golang_Dream/tree/master/Gin/Doc
	 Golang Gin 
 

Remarks: Only some important documents are posted here, please follow the above method to obtain the full PDF.

2020Gin Framework Chinese Document

@[toc]

installation

Before installing the Gin package, you need to install the Go environment on your computer and set up your workspace.

  1. First you need to install Go (support version 1.11+), and then use the following Go command to install Gin:
$ go get -u github.com/gin-gonic/gin
 
  1. Import the Gin package in your code:
import "github.com/gin-gonic/gin"
 
  1. (Optional) If you use http.StatusOKconstants such as , you need to import the net/httppackage:
import "net/http"
 

Quick start

#  example.go  
$ cat example.go
 
package main

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

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() //listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
 

API example

You can find many ready-made examples in the Gin example repository.

Use GET, POST, PUT, PATCH, DELETE and OPTIONS

func main() {
	//logger   recovery   gin  
	router := gin.Default()

	router.GET("/someGet", getting)
	router.POST("/somePost", posting)
	router.PUT("/somePut", putting)
	router.DELETE("/someDelete", deleting)
	router.PATCH("/somePatch", patching)
	router.HEAD("/someHead", head)
	router.OPTIONS("/someOptions", options)

	//  8080   PORT  .
	router.Run()
	// router.Run(":3000") hardcode  
}
 

Routing parameters

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

	// handler  /user/john  /user/ /user
	router.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "Hello %s", name)
	})

	// ,  /user/john/ /user/john/send
	// /user/john,  /user/john/
	router.GET("/user/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")
		message := name + " is " + action
		c.String(http.StatusOK, message)
	})

	// 
	router.POST("/user/:name/*action", func(c *gin.Context) {
		c.FullPath() == "/user/:name/*action" //true
	})

	router.Run(":8080")
}
 

Query string parameters

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

	//  request  
	//  URL: /welcome?firstname=Jane&lastname=Doe
	router.GET("/welcome", func(c *gin.Context) {
		firstname := c.DefaultQuery("firstname", "Guest")
		lastname := c.Query("lastname") //  c.Request.URL.Query().Get("lastname")  

		c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
	})
	router.Run(":8080")
}
 

Multipart/Urlencoded form

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

	router.POST("/form_post", func(c *gin.Context) {
		message := c.PostForm("message")
		nick := c.DefaultPostForm("nick", "anonymous")

		c.JSON(200, gin.H{
			"status":  "posted",
			"message": message,
			"nick":    nick,
		})
	})
	router.Run(":8080")
}
 

Other examples: query+post form

POST/post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=manu&message=this_is_great

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

	router.POST("/post", func(c *gin.Context) {

		id := c.Query("id")
		page := c.DefaultQuery("page", "0")
		name := c.PostForm("name")
		message := c.PostForm("message")

		fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
	})
	router.Run(":8080")
}
 

operation result:

id: 1234; page: 1; name: manu; message: this_is_great
 

Map as query string or post form parameter

POST/post?ids[a]=1234&ids[b]=hello HTTP/1.1
Content-Type: application/x-www-form-urlencoded

names[first]=thinkerou&names[second]=tianou
 
func main() {
	router := gin.Default()

	router.POST("/post", func(c *gin.Context) {

		ids := c.QueryMap("ids")
		names := c.PostFormMap("names")

		fmt.Printf("ids: %v; names: %v", ids, names)
	})
	router.Run(":8080")
}
 

operation result:

ids: map[b:hello a:1234], names: map[second:tianou first:thinkerou]
 

upload files

Single file

Refer to issue #774 and detailed example code: example code .

Use file.Filename with caution, refer to Content-Disposition on MDN and #1693

The file name of the uploaded file can be customized by the user, so it may contain illegal character strings. For the sake of safety, the file name rules should be unified by the server.

func main() {
	router := gin.Default()
	//  (  32 MiB)
	router.MaxMultipartMemory = 8 << 20  //8 MiB
	router.POST("/upload", func(c *gin.Context) {
		//single file
		file, _ := c.FormFile("file")
		log.Println(file.Filename)

		// 
		c.SaveUploadedFile(file, dst)

		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
	})
	router.Run(":8080")
}
 

curl test:

curl -X POST http://localhost:8080/upload/
  -F "file=@/Users/appleboy/test.zip"/
  -H "Content-Type: multipart/form-data"
 

Multiple files

Refer to the detailed example: example code.

func main() {
	router := gin.Default()
	//  (default is 32 MiB)
	router.MaxMultipartMemory = 8 << 20  //8 MiB
	router.POST("/upload", func(c *gin.Context) {
		// 
		form, _ := c.MultipartForm()
		files := form.File["upload[]"]

		for _, file := range files {
			log.Println(file.Filename)

			//
			c.SaveUploadedFile(file, dst)
		}
		c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
	})
	router.Run(":8080")
}
 

curl test:

curl -X POST http://localhost:8080/upload/
  -F "upload[]=@/Users/appleboy/test1.zip"/
  -F "upload[]=@/Users/appleboy/test2.zip"/
  -H "Content-Type: multipart/form-data"
 

Routing packet

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

	//Simple group: v1
	v1 := router.Group("/v1")
	{
		v1.POST("/login", loginEndpoint)
		v1.POST("/submit", submitEndpoint)
		v1.POST("/read", readEndpoint)
	}

	//Simple group: v2
	v2 := router.Group("/v2")
	{
		v2.POST("/login", loginEndpoint)
		v2.POST("/submit", submitEndpoint)
		v2.POST("/read", readEndpoint)
	}

	router.Run(":8080")
}
 

The default blank Gin without middleware

use:

r := gin.New()
 

instead

//  Logger and Recovery  
r := gin.Default()
 

Use middleware

func main() {
	// 
	r := gin.New()

	// 
	//Logger   gin.DefaultWriter   GIN_MODE=release.
	//  gin.DefaultWriter = os.Stdout
	r.Use(gin.Logger())

	//Recovery   panic   panic  500  
	r.Use(gin.Recovery())

	// 
	r.GET("/benchmark", MyBenchLogger(), benchEndpoint)

	// 
	//authorized := r.Group("/", AuthRequired())
	// 
	authorized := r.Group("/")
	//    "authorized"  
	//  AuthRequired()  
	authorized.Use(AuthRequired())
	{
		authorized.POST("/login", loginEndpoint)
		authorized.POST("/submit", submitEndpoint)
		authorized.POST("/read", readEndpoint)

		// 
		testing := authorized.Group("testing")
		testing.GET("/analytics", analyticsEndpoint)
	}

	//  0.0.0.0:8080
	r.Run(":8080")
}
 

How to write to the log file

func main() {
    // 
    gin.DisableConsoleColor()

    // 
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f)

    // 
    //gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

    router := gin.Default()
    router.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })

    router.Run(":8080")
}
 

Custom log format

func main() {
	router := gin.New()

	//LoggerWithFormatter   gin.DefaultWriter
	//  gin.DefaultWriter = os.Stdout
	router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {

		// 
		return fmt.Sprintf("%s - [%s]/"%s %s %s %d %s/"%s\" %s\"\n",
				param.ClientIP,
				param.TimeStamp.Format(time.RFC1123),
				param.Method,
				param.Path,
				param.Request.Proto,
				param.StatusCode,
				param.Latency,
				param.Request.UserAgent(),
				param.ErrorMessage,
		)
	}))
	router.Use(gin.Recovery())

	router.GET("/ping", func(c *gin.Context) {
		c.String(200, "pong")
	})

	router.Run(":8080")
}
 

Sample output:

::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET/ping HTTP/1.1 200 122.767 s "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
 

Controlling Log output coloring

By default, the log output on the console should be colored according to the detected TTY.

The log is not colored:

func main() {
    // 
    gin.DisableConsoleColor()
    
    //  gin :
    //logger   recovery (crash-free)  
    router := gin.Default()
    
    router.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })
    
    router.Run(":8080")
}
 

Color the log:

func main() {
    //
    gin.ForceConsoleColor()
    
    //  gin :
    //logger   recovery (crash-free)  
    router := gin.Default()
    
    router.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })
    
    router.Run(":8080")
}
 

Model binding and verification

To bind the request body to the structure, please use model binding. Currently, binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz) is supported.

Gin uses go-playground/validator.v8 to validate the parameters, click here to view the full document here

You need to set the tag on the bound field. For example, if the binding format is json, it needs to be set to json:"fieldname"

In addition, Gin provides two binding methods:

  • Type-Must bind

    • Methods-Bind, BindJSON, BindXML, BindQuery, BindYAML, BindHeader
    • Behavior - These methods use the bottom MustBindWith, if there is an error bound, the following instruction will be aborted request c.AbortWithError(400, err).SetType(ErrorTypeBind), response status code is set to 400, the request header Content-Typeis set text/plain; charset=utf-8. Note that if you try to set the response code after this, a warning will be issued [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422. If you want to better control the behavior, please use the ShouldBuind method.
  • Type-Should bind

    • Methods-ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML, ShouldBindHeader.
    • Behavior-These methods are used at the bottom level ShouldBindWith. If there is a binding error, an error is returned, and the developer can handle the request and error correctly. When we use the binding method, Gin will Content-Typeinfer which binder to use. If you are sure what you are binding, you can use MustBindWithor BindingWith.

You can also specify modifiers of specific rules for the field. If a field is binding:"required"modified and the value of the field is empty when binding, an error will be returned.

//  JSON
type Login struct {
	User     string `form:"user" json:"user" xml:"user"  binding:"required"`
	Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

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

	//JSON   ({"user": "manu", "password": "123"})
	router.POST("/loginJSON", func(c *gin.Context) {
		var json Login
		if err := c.ShouldBindJSON(&json); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if json.User != "manu" || json.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	//XML   (
	//	<?xml version="1.0" encoding="UTF-8"?>
	//	<root>
	//		<user>user</user>
	//		<password>123</password>
	//	</root>)
	router.POST("/loginXML", func(c *gin.Context) {
		var xml Login
		if err := c.ShouldBindXML(&xml); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if xml.User != "manu" || xml.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// HTML  (user=manu&password=123)
	router.POST("/loginForm", func(c *gin.Context) {
		var form Login
		// content-type  
		if err := c.ShouldBind(&form); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if form.User != "manu" || form.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	//  0.0.0.0:8080
	router.Run(":8080")
}
 

Example request:

$ curl -v -X POST/
  http://localhost:8080/loginJSON/
  -H 'content-type: application/json'/
  -d '{ "user": "manu" }'
> POST/loginJSON HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.51.0
> Accept: */*
> content-type: application/json
> Content-Length: 18
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
< Date: Fri, 04 Aug 2017 03:51:31 GMT
< Content-Length: 100
<
{"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}
 

Skip verification:

When using the above curlcommand to run the above example, an error is returned, because the Passwordfields in the example are used binding:"required", if we usebinding:"-" , then it will not report an error. # Run the example.go file and visit 0.0.0.0:8080/ping on the browser (windows access: localhost:8080/ping) $ go run example.go

Public number: Golang DreamWorks

Asong is a Golang development engineer, focusing on Golang related technologies: Golang interview, Beego, Gin, Mysql, Linux, network, operating system, etc., dedicated to Golang development. Welcome to pay attention to the official account: Golang DreamWorks. Study together and progress together.

How to get the document: Directly reply to the backstage of the official account: Gin, you can get the latest Gin Chinese document. The author asong regularly maintains it.

At the same time, upload documents to personal github: github.com/sunsong2020...