如何用go中的formdata计算多部分文件请求的内容长度

时间:2017-11-23 09:35:48

标签: go multipartform-data multipart content-length http-content-length

目前正在尝试创建一个分段上传请求来上传png以及一些额外的身体参数。服务器正在返回响应:

  

请求正文不包含指定的字节数。拿到   142,827,预计146,836

显然计算出了问题。我不能为我的生活找出如何实际手动计算正文的内容长度并正确地为请求文件。请参阅下面的发送请求代码:

func signUp(email, username, password, profilePath string) account {
    session := createClient()

    capToke := captchaToken(session)

    solved := solveCaptcha(capToke, "example.com")

    if solved == failed {
        panic("Solve Failed")
    }
    extraParams := map[string]string{
        "Username":             username,
        "Age":                  string(random(18, 21)),
        "Gender":               "1",
        "EmailAddress":         email,
        "Password":             password,
        "ConfirmPassword":      password,
        "g-recaptcha-response": solved,
        "Recaptcha":            "",
        "ReceiveNewsletter":    "false",
    }

    req, err := makeFileUploadRequest("https://example.com", extraParams, "ProfileImage", profilePath)
    if err != nil {
        panic(err)
    }

    req.Header.Set("Host", "example.com")
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0")
    req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
    req.Header.Set("Accept-Language", "en-US,en;q=0.5")
    req.Header.Set("Accept-Encoding", "gzip, deflate, br")
    req.Header.Set("Referer", "https://example.com")
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("Upgrade-Insecure-Requests", "1")

    client := createClient()
    resp, err := client.Do(req)
    defer resp.Body.Close()
    if err != nil {
        panic(err)
    } else {
        var bodyContent []byte
        fmt.Println(resp.StatusCode)
        fmt.Println(resp.Header)
        resp.Body.Read(bodyContent)
        resp.Body.Close()
        fmt.Println(bodyContent)
    }
    var acc account

    acc.email = email
    acc.password = password
    acc.username = username

    return acc
}

func makeFileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    fileContents, err := ioutil.ReadAll(file)
    if err != nil {
        return nil, err
    }
    fi, err := file.Stat()
    if err != nil {
        return nil, err
    }
    file.Close()

    body := new(bytes.Buffer)
    writer := multipart.NewWriter(body)

    for key, val := range params {
        _ = writer.WriteField(key, val)
    }
    err = writer.Close()
    if err != nil {
        return nil, err
    }

    part, err := writer.CreateFormFile(paramName, fi.Name())
    if err != nil {
        return nil, err
    }
    ht, _ := http.NewRequest("POST", uri, body)
    ht.Header.Set("Content-Type", writer.FormDataContentType())
    writer.Close()
    return ht, err
}           

1 个答案:

答案 0 :(得分:1)

错误在以下几行:

ht, _ := http.NewRequest("POST", uri, body)
ht.Header.Set("Content-Type", writer.FormDataContentType())
writer.Close()

对NewRequest的调用识别出body是一个bytes.Buffer,并使用缓冲区的当前大小设置内容长度标头。

在对writer.Close()的调用中,最终的多部分边界被写入请求体。此边界不包含在先前在NewRequest调用中设置的内容长度中。

要解决此问题,请在创建请求之前关闭编写器:

writer.Close()
ht, _ := http.NewRequest("POST", uri, body)
ht.Header.Set("Content-Type", writer.FormDataContentType())