duanmiaosi0150 2017-11-23 09:35
浏览 165
已采纳

如何在Go中使用FormData计算多部分文件请求的内容长度

Currently trying to create a multipart upload request to upload a png along with some extra body params. The server is returning the response:

The request body did not contain the specified number of bytes. Got 142,827, expected 146,836

So obviously something is going wrong with the calculation. I can't for the life of me work out how to actually manually count the content length of the body and file correctly for the request. See below my code for sending request:

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条回答 默认 最新

  • dongxibo2095 2017-11-23 18:53
    关注

    The error is on these lines:

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

    The call to NewRequest recognizes that the body is a bytes.Buffer and sets the content length header using the current size of the buffer.

    The final multipart boundary is written to the request body in the call to writer.Close(). This boundary is not included in the content length set previously in the call to NewRequest.

    To fix the problem, close the writer before creating the request:

    writer.Close()
    ht, _ := http.NewRequest("POST", uri, body)
    ht.Header.Set("Content-Type", writer.FormDataContentType())
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?