Golang中net/http包POST请求的content-length与body长度不符问题

Golang中net/http包POST请求的content-length与body长度不符问题 我正在使用 net/http 模块向一个网站发送 POST 请求。通常它工作正常,但有时我会收到以下错误信息:

Post "<URL>": http: ContentLength=47 with Body length 0

这是服务器的问题还是我的代码问题?

3 回复

我们既不了解服务器,也不了解你的代码。因此很难说……

更多关于Golang中net/http包POST请求的content-length与body长度不符问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


深入研究标准库源代码,错误是在这里创建的。 如果需要,我可以分享我的代码,但我想问的是,是否存在一个已知的(或许是常见的)条件/原因会触发(即返回)这个错误?

这是你的代码问题。这个错误表明你设置了 Content-Length 头为 47,但实际请求体长度为 0,两者不匹配。

最常见的原因是你在创建请求后修改了请求体,但没有更新 Content-Length 头,或者请求体在发送前被意外清空。

问题示例

package main

import (
    "bytes"
    "net/http"
)

func main() {
    // 创建请求体
    body := bytes.NewBufferString("example request body data")
    
    // 创建请求
    req, err := http.NewRequest("POST", "https://example.com", body)
    if err != nil {
        panic(err)
    }
    
    // 错误:修改请求体但没有更新 Content-Length
    req.Body = bytes.NewBufferString("shorter") // 新body长度只有7字节
    
    // 此时 Content-Length 仍然是原body的长度,导致不匹配
    client := &http.Client{}
    resp, err := client.Do(req) // 这里可能报错
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
}

正确做法

方法1:让 http 包自动处理

package main

import (
    "bytes"
    "net/http"
)

func main() {
    // 直接使用 http.Post
    body := bytes.NewBufferString("example request body data")
    resp, err := http.Post("https://example.com", "application/json", body)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    // 或者使用 http.NewRequest 但不手动设置 Content-Length
    req, err := http.NewRequest("POST", "https://example.com", body)
    if err != nil {
        panic(err)
    }
    
    client := &http.Client{}
    resp, err = client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
}

方法2:需要修改请求体时重新创建请求

package main

import (
    "bytes"
    "net/http"
)

func main() {
    // 如果需要不同的请求体,重新创建请求
    newBody := bytes.NewBufferString("new body content")
    req, err := http.NewRequest("POST", "https://example.com", newBody)
    if err != nil {
        panic(err)
    }
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
}

方法3:使用 io.ReadSeeker 类型的请求体

package main

import (
    "bytes"
    "net/http"
)

func main() {
    // bytes.Reader 实现了 io.ReadSeeker
    body := bytes.NewReader([]byte("request body data"))
    
    req, err := http.NewRequest("POST", "https://example.com", body)
    if err != nil {
        panic(err)
    }
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
}

调试建议

检查你的代码中是否有以下情况:

  1. 在创建请求后重新赋值 req.Body
  2. 手动设置了 Content-Length
  3. 请求体被多次读取
  4. 使用了不可重读的请求体(如 bytes.Buffer 被读取后)

使用 http.NewRequest 时,如果请求体实现了 Len() 方法,net/http 包会自动计算并设置正确的 Content-Length。如果请求体被修改或替换,这个长度就会失效。

回到顶部