用mime/multipart上传file和value时出现了一个问题,用postman可以正常上传file和value,但是用net/http库上传时则出现了可以上传file会失败的情况,err为unexpected EOF,证明了问题出现在自己的client代码中
问题代码to := "http://" + host.Text + ":" + port.Text + "/blog/" + title.Text
// PostFile(full, flab.Text, to, kind.Text, kindCn.Text)
// 设置参数
bodyBuf := &bytes.Buffer{}
writer := multipart.NewWriter(bodyBuf)
// fn, _ := filename.Get()
part, err := writer.CreateFormFile("file", flab.Text)
if err != nil {
// 弹窗
return
}
// io.WriteString(part, string(full))
io.WriteString(part, string(full))
writer.WriteField("topicCn", kindCn.Text)
writer.WriteField("topicEn", kind.Text)
// fmt.Fprint(part, full)
// fmt.Println(string(full))
// defer writer.Close()
contentType := writer.FormDataContentType()
defer writer.Close()
resp, err := http.Post(to, contentType, bodyBuf)
if err != nil {
fmt.Println(err.Error())
return
}
defer resp.Body.Close()
switch resp.StatusCode {
case 200:
fmt.Println("ok")
case 400:
vts, _ := io.ReadAll(resp.Body)
fmt.Println(string(vts))
}
fmt.Println(resp.StatusCode)
问题分析
根据错误类型,可以推测问题出在了wirter或者part中,经过测试,找到了问题出在了writer里
我们写go代码一般有一个人习惯就是用 defer 关闭打开了的io.reader但是*multipart.Writer不可以呀用defer,因为要在发送请求前调用CLOSE,否则上传的数据会缺少EOF,导致后端读取出错。
to := "http://" + host.Text + ":" + port.Text + "/blog/" + title.Text
// PostFile(full, flab.Text, to, kind.Text, kindCn.Text)
// 设置参数
bodyBuf := &bytes.Buffer{}
writer := multipart.NewWriter(bodyBuf)
// fn, _ := filename.Get()
part, err := writer.CreateFormFile("file", flab.Text)
if err != nil {
// 弹窗
return
}
// io.WriteString(part, string(full))
io.WriteString(part, string(full))
writer.WriteField("topicCn", kindCn.Text)
writer.WriteField("topicEn", kind.Text)
// fmt.Fprint(part, full)
// fmt.Println(string(full))
// defer writer.Close()
contentType := writer.FormDataContentType()
writer.Close()
resp, err := http.Post(to, contentType, bodyBuf)
if err != nil {
fmt.Println(err.Error())
return
}
defer resp.Body.Close()
switch resp.StatusCode {
case 200:
fmt.Println("ok")
case 400:
vts, _ := io.ReadAll(resp.Body)
fmt.Println(string(vts))
}
fmt.Println(resp.StatusCode)
总结
使用io.reader 时用defer关键词来关闭
使用io.writer时要视情况而使用defer