错误

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

我还需要考虑借鉴下优秀的项目如何设计