我正在用 Go 编写一个 webhook 来解析 JSON 有效负载。我正在尝试记录原始有效负载,然后立即对其进行解码,但是当我尝试时它失败了。如果我分别执行这些操作,它们都可以独立正常工作。
有人可以解释为什么我不能使用ioutil.ReadAll和json.NewDecoder在一起?
func webhook(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body)
log.Printf("incoming message - %s", body)
var p payload
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&p)
if err != nil {
// Returns EOF
log.Printf("invalid payload - %s", err)
}
defer r.Body.Close()
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么我不能使用
ioutil.ReadAll和json.NewDecoder在一起?
请求正文是io.ReadCloser直接从网络连接读取或多或少字节的 。Body 的内容默认不存储在内存中。这就是为什么在您第一次阅读 Body 之后,下次尝试阅读它时,您会得到 EOF。
因此,如果您需要多次处理请求正文,您必须自己将内容存储到内存中,这就是您已经在做的事情:
body, _ := ioutil.ReadAll(r.Body)
Run Code Online (Sandbox Code Playgroud)
然后,您可以body根据需要多次重复使用,并且由于您可以使用 Body 内容作为[]byte值,因此您可以使用json.Unmarshal代替json.NewDecoder(...).Decode.
这与您的问题无关,但请不要忽略从 返回的错误ioutil.ReadAll。
您也可以删除该defer r.Body.Close()行,因为您不必在服务器处理程序中关闭请求正文。(强调我的)
对于服务器请求,请求正文始终为非零,但在没有正文时会立即返回 EOF。服务器将关闭请求正文。ServeHTTP 处理程序不需要。