Ginで受け取れるリクエストボディはストリームなので、一度Read
メソッドなどで読み出してしまうと空っぽになってしまう。従って、BindJSON
などのメソッドを読み出した後に使用するとEOF
エラーが発生することがある。たとえば以下。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.New()
router.POST("hoge", func(c *gin.Context) {
buf := make([]byte, 2048)
n, _ := c.Request.Body.Read(buf) // ここでRequest.Bodyを読み切ってしまっている
b := string(buf[0:n])
fmt.Println(b)
var params RequestParams
// BindJSONは内部でRequest.Bodyを再び読み出そうとするが
// Request.Bodyはすでに読み出されて空になっているため、ここでEOFエラーになる
if err := c.BindJSON(¶ms); err != nil {
uc.Warningf("Failed binding request parameters: %s", err.Error())
c.Status(http.StatusBadRequest)
return
}
c.JSON(200, params)
})
router.Run()
}
対策としては、ioutil.NopCloser
メソッドを使って読み出してしまったリクエストボディを書き戻すなど。
buf := make([]byte, 2048)
n, _ := c.Request.Body.Read(buf)
b := string(buf[0:n])
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(s)))
fmt.Println(b)