错误
http: invalid Read on closed Body
http: wrote more than the declared Content-Length
错误1 http: invalid Read on closed Body
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"io/ioutil"
"log"
)
func main() {
g := gin.Default()
g.POST("/test", func(ctx *gin.Context) {
copyCtx := ctx.Copy()
go func() {
var err error
var buf []byte
if buf, err = ioutil.ReadAll(copyCtx.Request.Body); err != nil {
log.Println(err)
return
}
fmt.Println(string(buf))
}()
})
g.Run(":8080")
}
或者
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
g := gin.Default()
g.POST("/test", func(ctx *gin.Context) {
copyCtx := ctx.Copy()
go func() {
err := handleJob(copyCtx)
if err != nil {
fmt.Println(err)
}
}()
})
g.Run(":8080")
}
func handleJob(ctx *gin.Context) (err error) {
reqData, err := ctx.GetRawData()
if err != nil {
fmt.Println("此处发生错误")
return err
}
fmt.Println(reqData)
return
}
当把 g := gin.Default() 给程 g := gin.New()时,会每次都报错
postman测试 POST请求 http://localhost:8080/test?timestamp=1648539106 数据塞: { "data": "test" }
图1
图2
错误2 http: wrote more than the declared Content-Length
package main
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type RecMsg struct {
Data string `json:"data"`
}
func main() {
g := gin.Default()
g.POST("/test", func(ctx *gin.Context) {
copyCtx := ctx.Copy()
go func() {
var a RecMsg
if err := ctx.ShouldBindJSON(&a); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"errMsg": err, "status": http.StatusInternalServerError})
return
}
err := handleReq(copyCtx, a)
if err != nil {
fmt.Println(err)
return
}
}()
ctx.JSON(http.StatusOK, gin.H{"msg": "", "status": http.StatusOK})
})
g.Run(":8080")
}
func handleReq(ctx *gin.Context, r RecMsg) (err error) {
fmt.Println(ctx.Query("timestamp"))
fmt.Println(r)
err = errors.New("测试错误")
return
}
postman测试 POST请求 http://localhost:8080/test?timestamp=1648539106 数据塞: { "data": "test" } 请求错误:
原因
1. 第一种情况copyCtx.Request.Body和ctx.GetRawData()【其实就是ioutil.ReadAll(c.Request.Body)】,开启协程,拷贝的上下文往下传,请求已经返回200重置,然后你再取body就是关闭的了。
很多博客写的gin 异步处理请求都要注意一下,在go func里面就不要再写ctx.Json了
2.
ctx.Copy()赋值出来的上下文交给了协程,然后
开了协程,直接返回200
然后context可能已经写了header,因为直接返回,
所以context(非并发安全)可能认为的 响应数据为0,因此
content-length: 0
但是后续又执行了 c.JSON() , body里面又有数据,
因此客户端解析包出错了,才会报上面那个错误,
这里我们即使错误了 在go func里面就不要将错误返回了,因为这里的情况服务端收到返回也没意义
修正后的代码:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
g := gin.Default()
g.POST("/test", func(ctx *gin.Context) {
copyCtx := ctx.Copy()
go func() {
handleJob(copyCtx)
}()
ctx.JSON(http.StatusOK, gin.H{"msg": "", "status": http.StatusOK})
})
g.Run(":8080")
}
func handleJob(ctx *gin.Context) {
reqData, err := ctx.GetRawData()
if err != nil {
fmt.Println(err)
}
fmt.Println(reqData)
}
我还需要考虑借鉴下优秀的项目如何设计