Gin 框架学习:模型绑定和验证

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

Gin使用 go-playground/validator.v8 进行验证。 查看标签用法的全部文档.

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

Gin提供了两类绑定方法:

  • Type - Must bind
    • Methods - BindBindJSONBindXMLBindQueryBindYAML
    • Behavior - 这些方法属于 MustBindWith 的具体调用。 如果发生绑定错误,则请求终止,并触发 c.AbortWithError(400, err).SetType(ErrorTypeBind)。响应状态码被设置为 400 并且 Content-Type 被设置为 text/plain; charset=utf-8。 如果您在此之后尝试设置响应状态码,Gin会输出日志 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422。 如果您希望更好地控制绑定,考虑使用 ShouldBind 等效方法。
  • Type - Should bind
    • Methods - ShouldBindShouldBindJSONShouldBindXMLShouldBindQueryShouldBindYAML
    • Behavior - 这些方法属于 ShouldBindWith 的具体调用。 如果发生绑定错误,Gin 会返回错误并由开发者处理错误和请求。

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

分类至 GO
0条评论

Gin 框架学习:查询字符串参数

使用 c.Queryc.DefaultQuery 获取 URL 地址中的参数,代码:

package main

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

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

	// 使用现有的基础请求对象解析查询字符串参数。
	// 示例 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")
}

 

分类至 GO
0条评论

Gin 框架学习:映射查询字符串或表单参数

映射查询字符串或表单参数,类似于 PHP 的字符串下标数组参数。代码:

package main

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

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

用 curl 发送请求:

$ curl 'http://localhost:8080/post?ids[a]=1234&ids[b]=hello' -X POST -d 'names[first]=thinkerou&names[second]=tianou'

服务端控制台输出:

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

 

分类至 GO
0条评论

Gin 框架学习:将 request body 绑定到不同的结构体中

一般通过调用 c.Request.Body 方法绑定数据,但不能多次调用这个方法。

要想多次绑定,可以使用 c.ShouldBindBodyWith.

  • c.ShouldBindBodyWith 会在绑定之前将 body 存储到上下文中。 这会对性能造成轻微影响,如果调用一次就能完成绑定的话,那就不要用这个方法。
  • 只有某些格式需要此功能,如 JSONXMLMsgPackProtoBuf。 对于其他格式, 如 QueryFormFormPostFormMultipart 可以多次调用 c.ShouldBind() 而不会造成任任何性能损失 (详见 #1341)。
分类至 GO
0条评论

Gin 框架学习:记录访问日志

将访问日志写入到文件:

package main

import (
	"io"
	"os"

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

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

注意:如果服务重启,日志文件会被覆盖。

分类至 GO
0条评论

Gin 框架学习:在中间件中使用 Goroutine

当在中间件或 handler 中启动新的 Goroutine 时,不能使用原始的上下文,必须使用只读副本。

package main

import (
	"log"
	"time"

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

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

	r.GET("/long_async", func(c *gin.Context) {
		// 创建在 goroutine 中使用的副本
		cCp := c.Copy()
		go func() {
			// 用 time.Sleep() 模拟一个长任务。
			time.Sleep(5 * time.Second)

			// 请注意您使用的是复制的上下文 "cCp",这一点很重要
			log.Println("Done! in path " + cCp.Request.URL.Path)
		}()
	})

	r.GET("/long_sync", func(c *gin.Context) {
		// 用 time.Sleep() 模拟一个长任务。
		time.Sleep(5 * time.Second)

		// 因为没有使用 goroutine,不需要拷贝上下文
		log.Println("Done! in path " + c.Request.URL.Path)
	})

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

 

分类至 GO
0条评论

Gin 框架学习:只绑定 url 查询字符串

url 参数除了通过 c.Query() 或 c.DefaultQuery() 获取值,还可以绑定到结构体。

c.ShouldBindQuery() 函数只绑定 url 查询参数而忽略 post 数据。

示例代码:

package main

import (
	"log"

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

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

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

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

 

分类至 GO
0条评论

Gin 框架学习:使用 HTTP 方法

Gin 框架支持的 HTTP 方法有:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS

func main() {
	// 禁用控制台颜色
	// gin.DisableConsoleColor()

	// 使用默认中间件(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)

	// Any 表示此 url 接受任意 HTTP 方法
	router.Any("/any", any)

	// 默认在 8080 端口启动服务,除非定义了一个 PORT 的环境变量。
	router.Run()
	// router.Run(":3000") hardcode 端口号
}

 

分类至 GO
0条评论

小程序 wx.requestSubscribeMessage 调起订阅消息界面

微信小程序的订阅消息接口 wx.requestSubscribeMessage,只能是用户发生点击行为或者发起支付回调后,才可以调起订阅消息界面。

除去支付回调这种情况,你必须给页面某个元素绑定 tap 事件,把这个 API 放到 tap 事件里,当用户去点击这个元素时才能调起订阅消息界面,且不能通过 setTimeout 延迟执行。

有一种特殊情况,wx.showModal 模态窗口的 success 回调可以调起订阅消息界面,举例如下:

wx.showModal({
    showCancel: false,
    content: '操作成功',
    success: res => {
        wx.requestSubscribeMessage({
            tmplIds: [''],
            success: res => { }
        })
    }
})

 

分类至 小程序
0条评论