gin
gin copied to clipboard
README.md error errA := c.ShouldBindBodyWith(&objA, binding.Form)
- With issues:
type formA struct {
Foo string
json:"foo" xml:"foo" binding:"required"
} objA := formA{} c.ShouldBindBodyWith(&objA, binding.Form) cant use binding.Form should use binding.JSON maybe
Description
How to reproduce
package main
import (
"context"
"errors"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
c.Set("example", "12345")
// before request
c.Next()
// after request
latency := time.Since(t)
log.Println(latency)
}
}
func main() {
r := gin.Default()
// 中间件测试
r.Use(Logger())
r.StaticFS("/assets", http.Dir("assets"))
r.GET("/local/file", func(c *gin.Context) {
c.File("main.go")
})
r.POST("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
log.Println(example)
type formA struct {
Foo string `json:"foo" xml:"foo" binding:"required"`
}
type formB struct {
Bar string `json:"bar" xml:"bar" binding:"required"`
}
objA := formA{}
objB := formB{}
// This reads c.Request.Body and stores the result into the context.
if errA := c.ShouldBindBodyWith(&objA, binding.Form); errA == nil {
c.String(http.StatusOK, `the body should be formA`)
// At this time, it reuses body stored in the context.
} else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
c.String(http.StatusOK, `the body should be formB JSON`)
// And it can accepts other formats
} else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
c.String(http.StatusOK, `the body should be formB XML`)
}
// c.Redirect(http.StatusFound, "/someDataFromReader")
})
r.GET("/long_async", func(c *gin.Context) {
cCp := c.Copy()
go func() {
time.Sleep(5 * time.Second)
log.Println("Done! in path " + cCp.Request.URL.Path)
}()
})
r.GET("/someDataFromReader", func(c *gin.Context) {
response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png")
if err != nil || response.StatusCode != http.StatusOK {
c.Status(http.StatusServiceUnavailable)
return
}
reader := response.Body
defer reader.Close()
contentLength := response.ContentLength
contentType := response.Header.Get("Content-Type")
extraHeaders := map[string]string{
"Content-Disposition": `attachment; filename="gopher.png"`,
}
c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
})
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
// gin.H is a shortcut for map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
names := []string{"lena", "austin", "foo"}
// Will output : while(1);["lena","austin","foo"]
c.SecureJSON(http.StatusOK, names)
})
r.GET("/moreJSON", func(c *gin.Context) {
// You also can use a struct
var msg struct {
Name string `json:"user"`
Message string
Number int
}
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
// Note that msg.Name becomes "user" in the JSON
// Will output : {"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})
})
// 优雅启动或者关闭
srv := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20, // 2 的 20次方
}
// 协程启动服务
go func() {
if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
log.Printf("listen:%s\n", err)
}
}()
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
// 延迟关闭
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exiting")
}
Expectations
cannot use binding.Form (variable of type binding.formBinding) as binding.BindingBody value in argument to c.ShouldBindBodyWith: binding.formBinding does not implement binding.BindingBody (missing method BindBody)
Actual result
Environment
- go version:1.19
- gin version (or commit ref):1.8.1
- operating system:windows
looks like it is a kind of typo in README. obviously binding.Form doesn't have BindBody method and it doesn't implement BindingBody interface.
c.ShouldBindBodyWith(&objA, binding.Form)
My PR: https://github.com/gin-gonic/gin/pull/3312 however I think it is possible to update README and delete this feature for binding.Form