gin多次绑定请求参数
package main
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// resp 返回
func resp(c *gin.Context, code int, msg string) {
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": msg,
"nowtime": time.Now().Unix(),
})
}
// AuthMiddleware 认证中间件
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 中间件内bind参数
var l loginReq
if err := c.ShouldBind(&l); err != nil {
fmt.Println("err: ", err)
c.Abort()
}
if l.UserName == "" && l.Password == "" {
c.Abort()
}
}
}
// login 登录逻辑
func login(c *gin.Context) {
// 逻辑内再次bind参数
// 此时这里的shouldBind会出错, 错误是: EOF
var lr loginReq
if err := c.ShouldBind(&lr); err != nil {
fmt.Printf("bind params err: %v\n", err)
resp(c, -1, err.Error())
return
}
resp(c, 0, fmt.Sprintf("%s login success!", lr.UserName))
return
}
// loginReq 请求参数
type loginReq struct {
UserName string `json:"username"`
Password string `json:"password"`
}
func main() {
e := gin.Default()
// 注册全局中间件
e.Use(authMiddleware())
e.POST("/api/v1/login", login)
e.Run(":8080")
}
请求验证:
curl -XPOST 'http://127.0.0.1:8080/api/v1/login' \
-H 'Content-Type: application/json' \
-d '{
"username":"zhangsan",
"password":"123456"
}'
响应:
{
"code": -1,
"msg": "EOF",
"nowtime": 1662451101
}
一、 使用ShouldBindBodyWith解决
// tips:
// c.ShouldBindBodyWith在绑定之前将 body 存储到上下文中。这对性能有轻微的影响,因此如果您足够一次调用绑定,则不应使用此方法。
package main
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// resp 返回
func resp(c *gin.Context, code int, msg string) {
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": msg,
"nowtime": time.Now().Unix(),
})
}
// AuthMiddleware 认证中间件
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 中间件内bind参数
var l loginReq
if err := c.ShouldBindBodyWith(&l, binding.JSON); err != nil {
fmt.Println("err: ", err)
c.Abort()
}
if l.UserName == "" && l.Password == "" {
c.Abort()
}
}
}
// login 登录逻辑
func login(c *gin.Context) {
// 逻辑内再次bind参数
// 此时这里的shouldBind不会出错
var lr loginReq
if err := c.ShouldBindBodyWith(&lr, binding.JSON); err != nil {
fmt.Printf("bind params err: %v\n", err)
resp(c, -1, err.Error())
return
}
resp(c, 0, fmt.Sprintf("%s login success!", lr.UserName))
return
}
// loginReq 请求参数
type loginReq struct {
UserName string `json:"username"`
Password string `json:"password"`
}
func main() {
e := gin.Default()
// 注册全局中间件
e.Use(authMiddleware())
e.POST("/api/v1/login", login)
e.Run(":8080")
}
二、 转存Body
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// resp 返回
func resp(c *gin.Context, code int, msg string) {
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": msg,
"nowtime": time.Now().Unix(),
})
}
// AuthMiddleware 认证中间件
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 先把body取出来
data, err := c.GetRawData()
if err != nil {
fmt.Println("read body failed, error: ", err)
}
// bind之前把body写回去
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
var l loginReq
if err := c.ShouldBind(&l); err != nil {
fmt.Println("err: ", err)
c.Abort()
}
// bind之后把body写回去
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
if l.UserName == "" && l.Password == "" {
c.Abort()
}
}
}
// login 登录逻辑
func login(c *gin.Context) {
// 逻辑内再次bind参数
// 此时这里的shouldBind不会出错
var lr loginReq
if err := c.ShouldBind(&lr); err != nil {
fmt.Printf("bind params err: %v\n", err)
resp(c, -1, err.Error())
return
}
resp(c, 0, fmt.Sprintf("%s login success!", lr.UserName))
return
}
// loginReq 请求参数
type loginReq struct {
UserName string `json:"username"`
Password string `json:"password"`
}
func main() {
e := gin.Default()
// 注册全局中间件
e.Use(authMiddleware())
e.POST("/api/v1/login", login)
e.Run(":8080")
}