Go发送携带二进制文件的HTTP POST请求问题及解决方案
问题描述
需要构造携带二进制文件数据的HTTP POST请求,用于对接DeepStack图像处理服务,已实现可正常运行的Python版本,代码如下:
image_data = open(file,"rb").read() try: response = requests.post("http://deepstack.local:82/v1/vision/detection",files={"image":image_data},timeout=15).json()
最初实现Go版本时参考了发送JSON格式POST请求的基础示例,结合自身场景修改后的核心代码如下:
data, err := ioutil.ReadFile(tempPath + file.Name()) if err != nil { log.Print(err) } httpposturl := "http://deepstack.local:82/v1/vision/custom/combined" fmt.Println("HTTP JSON POST URL:", httpposturl) var jsonData = []byte(`{"image": ` + data + `}`) request, error := http.NewRequest("POST", httpposturl, bytes.NewBuffer(jsonData)) request.Header.Set("Content-Type", "application/json; charset=UTF-8")
运行上述代码触发如下报错:
invalid operation:
{"image":+ data (mismatched types untyped string and []byte)
代码中data变量类型为[]uint8(即[]byte),报错根源是尝试拼接字符串和字节切片两种不兼容的数据类型。尝试过多种修改方案:包括将jsonData声明为byte类型、将data转换为string、使用os.Open替代ioutil.ReadFile等均未成功,也未找到携带二进制数据的POST请求相关参考示例。
解决方案
问题核心是Python版本通过files参数发送的是multipart/form-data格式的请求,并非JSON格式,之前的Go代码错误尝试将二进制图片数据直接拼入JSON字符串,且设置了错误的Content-Type,和DeepStack服务要求的请求格式不匹配。
正确实现方式是构造标准的multipart表单请求,将图片作为表单文件字段上传,可运行的完整代码如下:
package main import ( "bytes" "fmt" "io" "io/ioutil" "mime/multipart" "net/http" "os" ) func createMultipartFormData(fieldName, fileName string) (bytes.Buffer, *multipart.Writer) { var b bytes.Buffer var err error w := multipart.NewWriter(&b) var fw io.Writer file := mustOpen(fileName) if fw, err = w.CreateFormFile(fieldName, file.Name()); err != nil { fmt.Println("Error: ", err) } if _, err = io.Copy(fw, file); err != nil { fmt.Println("Error: ", err) } w.Close() return b, w } func mustOpen(f string) *os.File { r, err := os.Open(f) if err != nil { pwd, _ := os.Getwd() fmt.Println("PWD: ", pwd) panic(err) } return r } func main() { url := "http://deepstack.local:82/v1/vision/custom/combined" b, w := createMultipartFormData("image", "C:\\go_sort\\temp\\person.jpg") req, err := http.NewRequest("POST", url, &b) if err != nil { return } // 必须设置正确的Content-Type,值中包含表单分隔符boundary req.Header.Set("Content-Type", w.FormDataContentType()) client := &http.Client{} response, err := client.Do(req) if err != nil { panic(err) } defer response.Body.Close() fmt.Println("response Status:", response.Status) fmt.Println("response Headers:", response.Header) body, _ := ioutil.ReadAll(response.Body) fmt.Println("response Body:", string(body)) }
使用时只需将代码中的服务地址、本地图片文件路径替换为实际有效值,即可正常从响应体中获取DeepStack返回的处理结果。
内容的提问来源于stack exchange,提问作者BeanBagKing
相关产品推荐
相关产品推荐

