gin框架学习笔记

本文是关于Gin框架的学习笔记,介绍了 Gin 的高速路由、中间件支持、JSON处理、模型绑定与验证等功能。 Gin 默认使用 encoding/json 包,但可以替换为其他库如jsoniter。还探讨了 Gin 的中间件、重定向、Goroutines的使用以及如何自定义HTTP配置和日志格式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

gin框架学习笔记

官网review

  1. gin 是用go编写的web框架,由于httprputer(基于radix树路由)速度快了40倍,支持中间件,路由组处理,json等多方式验证,内置了json/xml/html等渲染,是一个易于使用的go 框架
  2. 如果是用常量,比如http.statusOk impport “net/http”
  3. gin使用默认的encoding/json作为默认的json包,但是可以通过其他标签构建改变他 (jsoniter: https://github.com/json-iterator/go)
    Replace(性能更棒)
import "encoding/json"
json.Marshal(&data)

with

import jsoniter "github.com/json-iterator/go"

var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Marshal(&data)

Replace

import "encoding/json"
json.Unmarshal(input, &data)

with

import jsoniter "github.com/json-iterator/go"

var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Unmarshal(input, &data)

4.gin默认开启msgPack渲染功能,关闭这个功能通过建立指定nomsgpack标签

 go build -tags=nomsgpack .

5.参数

 // path
 name := c.Param("name")
// query
firstname := c.DefaultQuery("firstname", "Guest")
lastname := c.Query("lastname")
// body
// Content-Type: application/x-www-form-urlencoded
message := c.PostForm("message")

6.中间件

// 默认创建一个没有任何中间件的路由器
	r  :=  gin . New ()
	r.Use(gin.Logger())
  1. 模型绑定和验证
    将请求body绑定请求类型,支持绑定,json,xml,yaml和
    Gin 使用go-playground/validator/v10进行验证(https://github.com/go-playground/validator)
    __NOTE: __ 需要绑定相应的标签在所有的字段上,如果想要绑定的话
    gin tingeing2种设置方式去绑定(一定要绑定和应该要绑定)
  2. 一定要绑定
    方法:Bind, BindJSON, BindXML, BindQuery, BindYAML, BindHeader
    行为: 如没有绑定将导致请求中指,并且使用c.AbortWithError(400, err).SetType(ErrorTypeBind)
  3. 应该要绑定
    方法: ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML, ShouldBindHeader
    行为:这些方法ShouldBindWith在后台使用。如果存在绑定错误,则返回错误,开发人员有责任适当地处理请求和错误。
// 默认创建一个没有任何中间件的路由器
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()

	// Example for binding 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"})
	})
	
	// Listen and serve on 0.0.0.0:8080
	router.Run(":8080")
}

绑定query和body

type Person struct {
	Name    string `form:"name" json:"name"`
	Address string `form:"address" json:"address"`
}

func main() {
	route := gin.Default()
	route.GET("/testing", startPage)
	route.Run(":8085")
}

func startPage(c *gin.Context) {
	var person Person
	if c.Bind(&person) == nil {
		log.Println("====== Bind By Query String ======")
		log.Println(person.Name)
		log.Println(person.Address)
	}

	if c.BindJSON(&person) == nil {
		log.Println("====== Bind By JSON ======")
		log.Println(person.Name)
		log.Println(person.Address)
	}

	c.String(200, "Success")
}

8.重定向
内部和外部发送请求都是简单的,内部和外部都是支持的
会有坑需要注意(https://github.com/gin-gonic/gin/issues/444)

// 外部
r.GET("/test", func(c *gin.Context) {
	c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})
// 内部
r.POST("/test", func(c *gin.Context) {
	c.Redirect(http.StatusFound, "/foo")
})

9.中间件

  1. 简单中间件(默认gin.Default()/自定义gin.New())
// 自定义中间件
func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()

		// Set example variable
		c.Set("example", "12345")

		// before request

		c.Next()

		// after request
		latency := time.Since(t)
		log.Print(latency)

		// access the status we are sending
		status := c.Writer.Status()
		log.Println(status)
	}
}

func main() {
	r := gin.New()
	r.Use(Logger())

	r.GET("/test", func(c *gin.Context) {
		example := c.MustGet("example").(string)

		// it would print: "12345"
		log.Println(example)
	})

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}
// 默认中间件
func main() {
	r := gin.Default()

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

10.Goroutines中间件
当内部使用一个新的在中间件Goroutines处理程序时,您不应该使用其中的原始上下文,您必须使用只读副本。

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

	r.GET("/long_async", func(c *gin.Context) {
		// create copy to be used inside the goroutine
		cCp := c.Copy()
		go func() {
			// simulate a long task with time.Sleep(). 5 seconds
			time.Sleep(5 * time.Second)

			// note that you are using the copied context "cCp", IMPORTANT
			log.Println("Done! in path " + cCp.Request.URL.Path)
		}()
	})

	r.GET("/long_sync", func(c *gin.Context) {
		// simulate a long task with time.Sleep(). 5 seconds
		time.Sleep(5 * time.Second)

		// since we are NOT using a goroutine, we do not have to copy the context
		log.Println("Done! in path " + c.Request.URL.Path)
	})

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

11.自定义 HTTP 配置

func main() {
	router := gin.Default()
	http.ListenAndServe(":8080", router)
}
or

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

	s := &http.Server{
		Addr:           ":8080",
		Handler:        router,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	s.ListenAndServe()
}

12.使用 Gin 运行多项服务

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)

var (
	g errgroup.Group
)

func router01() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 01",
			},
		)
	})

	return e
}

func router02() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 02",
			},
		)
	})

	return e
}

func main() {
	server01 := &http.Server{
		Addr:         ":8080",
		Handler:      router01(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	server02 := &http.Server{
		Addr:         ":8081",
		Handler:      router02(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	g.Go(func() error {
		err := server01.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			log.Fatal(err)
		}
		return err
	})

	g.Go(func() error {
		err := server02.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			log.Fatal(err)
		}
		return err
	})

	if err := g.Wait(); err != nil {
		log.Fatal(err)
	}
}

12.定义路由日志格式
路由的默认日志是:

[GIN-debug] POST   /foo                      --> main.main.func1 (3 handlers)
[GIN-debug] GET    /bar                      --> main.main.func2 (3 handlers)
[GIN-debug] GET    /status                   --> main.main.func3 (3 handlers)

修改日志格式使用,gin.DebugPrintRouteFunc函数

import (
	"log"
	"net/http"

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

func main() {
	r := gin.Default()
	gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
		log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)
	}

	r.POST("/foo", func(c *gin.Context) {
		c.JSON(http.StatusOK, "foo")
	})

	r.GET("/bar", func(c *gin.Context) {
		c.JSON(http.StatusOK, "bar")
	})

	r.GET("/status", func(c *gin.Context) {
		c.JSON(http.StatusOK, "ok")
	})

	// Listen and Server in http://0.0.0.0:8080
	r.Run()
}

设置获取cookie

import (
    "fmt"

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

func main() {

    router := gin.Default()

    router.GET("/cookie", func(c *gin.Context) {

        cookie, err := c.Cookie("gin_cookie")

        if err != nil {
            cookie = "NotSet"
            c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)
        }

        fmt.Printf("Cookie value: %s \n", cookie)
    })

    router.Run()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值