首页 > 其他分享 >golang-Gin

golang-Gin

时间:2025-01-18 15:21:45浏览次数:1  
标签:http func router golang JSON Context gin Gin

路由

参数匹配

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)
	})

	// 此 handler 将匹配 /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.Run(":8080")
}

路由组

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

	// 简单的路由组: v1
	v1 := router.Group("/v1")
	{
		v1.POST("/login", loginEndpoint)
		v1.POST("/submit", submitEndpoint)
		v1.POST("/read", readEndpoint)
	}

	// 简单的路由组: v2
	v2 := router.Group("/v2")
	{
		v2.POST("/login", loginEndpoint)
		v2.POST("/submit", submitEndpoint)
		v2.POST("/read", readEndpoint)
	}

	router.Run(":8080")
}

中间件

是位于路由请求处理函数之前或之后执行的处理过程,作用如下。

  1. 日志记录:记录请求的相关信息,如请求方法、路径、时间等。
  2. 身份验证和授权:检查用户是否有权访问特定的路由或资源。
  3. 数据处理和转换:对请求或响应的数据进行预处理或修改。
  4. 错误处理:捕获和处理在请求处理过程中可能出现的错误。
  5. 性能监控:测量请求的处理时间等性能指标。

在使用 Gin 框架时,可以使用中间件来为一组路由或整个应用添加通用的处理逻辑,而无需在每个具体的路由处理函数中重复编写相同的代码。设置中间件的方式如下。

func main() {
	// 新建一个没有任何默认中间件的路由
	r := gin.New()

	// 全局中间件
	// Logger 中间件将日志写入 gin.DefaultWriter,即使你将 GIN_MODE 设置为 release。
	// By default gin.DefaultWriter = os.Stdout
	r.Use(gin.Logger())

	// Recovery 中间件会 recover 任何 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")
}

next() 函数通常用于控制中间件的执行流程。当在一个中间件函数中调用 next() 函数时,它会将控制权传递给下一个中间件或最终的路由处理函数。如果没有调用 next() ,则后续的中间件和路由处理函数将不会被执行。

通过这种方式,可以在中间件中进行一些预处理操作,然后决定是否继续执行后续的处理逻辑。

package main

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

func myMiddleware(c *gin.Context) {
    // 在此处进行一些预处理操作
    println("在中间件中进行预处理")

    // 调用 next 函数,将控制权传递给后续的中间件或路由处理函数
    next(c)

    // 在此处进行一些后续处理操作
    println("在中间件中进行后续处理")
}

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

    // 使用中间件
    r.Use(myMiddleware)

    r.GET("/hello", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello, World!",
        })
    })

    r.Run(":8080")
}

请求参数绑定

GET/POST请求参数绑定

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")
}

模型绑定和验证

要将请求体绑定到结构体中,使用模型绑定。 Gin目前支持JSON、XML、YAML和标准表单值的绑定(foo=bar&boo=baz)。

使用时,需要在要绑定的所有字段上,设置相应的tag。 例如,使用 JSON 绑定时,设置字段标签为 json:"fieldname"。

Gin提供了两类绑定方法。

Must bind

  • Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML,BindBody
  • Behavior - 这些方法属于 MustBindWith 的具体调用。 如果发生绑定错误,则请求终止,并触发 c.AbortWithError(400, err).SetType(ErrorTypeBind)。响应状态码被设置为 400 并且 Content-Type 被设置为 text/plain; charset=utf-8。

Should bind

  • Methods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML,ShouldBindBody
  • Behavior - 这些方法属于 ShouldBindWith 的具体调用。 如果发生绑定错误,Gin 会返回错误并由开发者处理错误和请求。

使用 Bind 、ShouldBind方法时,Gin 会尝试根据 Content-Type 推断如何绑定。 如果你明确知道要绑定什么,可以使用特定类型的 MustBindWith 或 ShouldBindWith。

你也可以指定必须绑定的字段。 如果一个字段的 tag 加上了 binding:"required",但绑定时是空值, Gin 会报错。

// 绑定 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>manu</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 Header 推断使用哪个绑定器。
		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")
}

绑定HTML复选框

...

type myForm struct {
    Colors []string `form:"colors[]"`
}

...

func formHandler(c *gin.Context) {
    var fakeForm myForm
    c.ShouldBind(&fakeForm)
    c.JSON(200, gin.H{"color": fakeForm.Colors})
}

...

绑定URI

package main

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

type Person struct {
	ID   string `uri:"id" binding:"required,uuid"`
	Name string `uri:"name" binding:"required"`
}

func main() {
	route := gin.Default()
	route.GET("/:name/:id", func(c *gin.Context) {
		var person Person
		if err := c.ShouldBindUri(&person); err != nil {
			c.JSON(400, gin.H{"msg": err.Error()})
			return
		}
		c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
	})
	route.Run(":8088")
}

响应渲染静态资源绑定

JSON响应

以JSON格式组织响应数据,如gin.Context.JSON()gin.Context.AsciiJSON()gin.Context.PureJSON()gin.Context.SecureJSON()

gin.Context.JSON()以标准的 JSON 格式响应数据。

package main

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

func main() {
    r := gin.Default()
    r.GET("/json", func(c *gin.Context) {
        data := gin.H{
            "message": "Hello, JSON!",
            "number":  42,
        }
        c.JSON(200, data)
    })
    r.Run(":8080")
}

gin.Context.AsciiJSON(),将数据编码为 ASCII 格式的 JSON 字符串。它会将非 ASCII 字符进行转义。

gin.Context.PureJSON()。通常,JSON 使用 unicode 替换特殊 HTML 字符,例如 < 变为 \ u003c。如果要按字面对这些字符进行编码,则可以使用 PureJSON。Go 1.6 及更低版本无法使用此功能。

gin.Context.SecureJSON(),主要用于防止 JSON 劫持等安全问题。在某些情况下,浏览器可能会误解 JSON 响应并将其错误地解释为脚本执行,SecureJSON 通常会添加一些预防措施来避免这种情况。

XML/JSON/YAML/ProtoBuf 响应渲染

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

	// gin.H 是 map[string]interface{} 的一种快捷方式
	r.GET("/someJSON", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
	})

	r.GET("/moreJSON", func(c *gin.Context) {
		// 你也可以使用一个结构体
		var msg struct {
			Name    string `json:"user"`
			Message string
			Number  int
		}
		msg.Name = "Lena"
		msg.Message = "hey"
		msg.Number = 123
		// 注意 msg.Name 在 JSON 中变成了 "user"
		// 将输出:{"user": "Lena", "Message": "hey", "Number": 123}
		c.JSON(http.StatusOK, msg)
	})

	r.GET("/someXML", func(c *gin.Context) {
		c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
	})

	r.GET("/someYAML", func(c *gin.Context) {
		c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
	})

	r.GET("/someProtoBuf", func(c *gin.Context) {
		reps := []int64{int64(1), int64(2)}
		label := "test"
		// protobuf 的具体定义写在 testdata/protoexample 文件中。
		data := &protoexample.Test{
			Label: &label,
			Reps:  reps,
		}
		// 请注意,数据在响应中变为二进制数据
		// 将输出被 protoexample.Test protobuf 序列化了的数据
		c.ProtoBuf(http.StatusOK, data)
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run(":8080")
}

html模板渲染响应

HTML 模板是包含固定的 HTML 结构以及可替换或动态部分的文件。这些可替换的部分通常使用特定的语法或标记来表示,以便在运行时插入动态数据。

Gin 框架中使用 HTML 模板的一般步骤如下。

  1. 创建模板文件:创建 .html 文件,例如 index.html ,在其中定义 HTML 结构,并使用特定的语法(如 {{.VariableName}} )来标记需要动态填充的部分。
  2. 加载模板:在 Gin 框架的初始化代码中,使用 LoadHTMLGlob 或 LoadHTMLFiles 方法加载模板文件。
r := gin.Default()
r.LoadHTMLGlob("templates/*")  // 加载 templates 目录下的所有模板文件
// 或者
r.LoadHTMLFiles("templates/index.html")  // 加载指定的模板文件
  1. 加载与使用html模板
r.GET("/", func(c *gin.Context) {
    data := gin.H{
        "Title": "My Page Title",
        "Content": "This is the content of the page.",
    }
    c.HTML(http.StatusOK, "index.html", data)  // 渲染模板并传递数据
})

设置静态资源

func main() {
	router := gin.Default()
	router.Static("/assets", "./assets")
	router.StaticFS("/more_static", http.Dir("my_file_system"))
	router.StaticFile("/favicon.ico", "./resources/favicon.ico")

	// 监听并在 0.0.0.0:8080 上启动服务
	router.Run(":8080")
}

设置日志

定义日志输出文件

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")
}

自定义日志格式,处理请求时会自动记录信息如请求方法、路径、状态码、请求花费时间

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")
}

自定义路由注册时日志打印的格式

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")
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run()
}

其他功能

上传文件、设置和获取cookie、goroutine的使用

http重定向、路由重定向

支持http2.0主动推送功能、使用JSONP实现跨域请求响应

标签:http,func,router,golang,JSON,Context,gin,Gin
From: https://www.cnblogs.com/essays/p/18678488

相关文章

  • AtCoder Beginner Contest 388
    A-A-?UPC题意给定字符串\(s\),输出\(s\)首个字符与\(UPC\)组成的字符串思路模拟代码点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongtypedefpair<int,int>pii;constintmxn=1e6+5;voidsolve(){ strings; ci......
  • Nginx proxy_pass 的一个注意点
    原文:Nginx中proxy_pass的作用以及注意事项格式proxy_pass格式:proxy_passURL。proxy_passhttp://www.xxx.com/;proxy_passhttp://192.168.200.101:8080/uri;proxy_passunix:/tmp/www.sock;注意假设Nginx服务器的域名为www.xxx.com,后端服务器为192.168.1.10。......
  • 漏洞预警 | WordPress Plugin Radio Player SSRF漏洞
    0x00漏洞编号CVE-2024-543850x01危险等级高危0x02漏洞概述WordPress插件RadioPlayer是一种简单而有效的解决方案,用于将实时流媒体音频添加到您的WordPress网站。0x03漏洞详情CVE-2024-54385漏洞类型:SSRF影响:获取敏感信息简述:RadioPlayer的/wp-admin/admin-......
  • golang 使用 http 连接池
    最近生产碰到的问题,A程序调用B服务某接口,在大流量场景下,B接口偶尔返回503,B是java写的,A是golang编写的。经沟通,B接口最大QPS为2000,且无优化空间,A这边大概20个并发线程,B加大了连接数配置。仍然是这样错误,‌503错误‌,即“服务不可用”,通常表示服务器暂时无法处理......
  • golang 指针传递和值传递
    golang指针传递和值传递packagemainimport"fmt"typeMyStructstruct{ Valuestring}//值传递//ModifyStructtakesaMyStructbyvalueandtriestomodifyit.funcModifyStruct(sMyStruct){ s.Value="Modified"}//指针传递//ModifySt......
  • nginx适配Overlay以及测试工具
    本文分享自天翼云开发者社区《nginx适配Overlay以及测试工具》,作者:pan Overlay与Underlay介绍Overlay网络和Underlay网络是一组相对概念,Overlay网络是建立在Underlay网络上的逻辑网络。而Overlay网络是通过网络虚拟化技术,在同一张Underlay网络上构建出的一张或者多张虚拟的逻......
  • Origin2018软件安装详细步骤(百度网盘)
    软件简介:Origin2018是由OriginLab公司开发等我,一款功能强大的科学绘图与数据分析软件,具有丰富的绘图模板、全面的数据分析功能以及便捷的操作方式。安装环境:Win11/Win10/Win8/Win7 百度网盘链接:https://pan.baidu.com/s/1Yxu6Iuo8LoQ685QD6TKHKQ 提取码:63e3安装......
  • 使用 Golang 编译 Linux 可运行文件
    Golang(或Go)是一种开源编程语言,因其简单、高效、并发编程支持而备受欢迎。本文将详细介绍如何使用Golang编译生成可以在Linux上运行的可执行文件。一、安装Golang1.1下载Golang从Golang官方网站下载适合你操作系统的安装包:Golang下载页面1.2安装Golang在Ubuntu......
  • VP AtCoder Beginner Contest 382
    A-DailyCookie题意:有\(n\)个盒子,有些盒子有蛋糕,被人吃了\(m\)个蛋糕,问有几个盒子没蛋糕。直接计算即可。点击查看代码voidsolve(){intn,m;std::cin>>n>>m;std::strings;std::cin>>s;std::cout<<n-std::count(s.begin(),s.end(),......
  • pinginfoview批量ping工具
    互联网各领域资料分享专区(不定期更新):Sheet前言由于内容较多,且不便于排版,为避免资源失效,请用手机点击链接进行保存,若链接生效请及时反馈,谢谢~正文链接如下(为避免资源失效,请用手机点击链接进行保存):夸克网盘分享......