HTTP Post containing binary data in golang

huangapple go评论178阅读模式
英文:

HTTP Post containing binary data in golang

问题

我希望我能解释清楚。我正在尝试进行包含二进制数据(文件)的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中,我从这里的基本示例开始:https://golangtutorial.dev/tips/http-post-json-go/

为了适应我的需求,我稍微修改了一下相关的代码:

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)。我意识到,在高层次上,问题出在哪里。我试图连接两种不同的数据类型。就是这样了。不过,我尝试了很多东西,我相信任何熟悉Go的人都会立即意识到是错误的(将jsonData声明为byte,将data转换为字符串,使用os.Open而不是ioutil.ReadFile等)。不过,我只是在盲目地摸索。我找不到一个不使用普通字符串作为JSON数据的示例。

我会感激任何想法。

--- 答案 ---

我将Dietrich Epp的答案标记为接受,因为他给了我我所要求的。然而,评论中的RedBlue给了我我实际需要的。谢谢你们两个。下面的代码稍作修改,来自这个答案:https://stackoverflow.com/a/56696333/2707357

将url变量更改为您的DeepStack服务器,文件名更改为实际存在的文件名,响应正文应返回所需的信息。

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
    }
    // Don't forget to set the content type, this will contain the boundary.
    req.Header.Set("Content-Type", w.FormDataContentType())

    client := &http.Client{}
    response, error := client.Do(req)
    if err != nil {
        panic(error)
    }
    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))
}

希望对你有所帮助。

英文:

I hope I can explain this right. I'm trying to make an HTTP post request that contains binary data (a file). This is for DeepStack image processing. In Python I have the following working:

image_data = open(file,"rb").read()
        try:
            response = requests.post("http://deepstack.local:82/v1/vision/detection",files={"image":image_data},timeout=15).json()

In Go, I started with the basic example from here: https://golangtutorial.dev/tips/http-post-json-go/

Modifying this a bit for my use, the relevant lines are:

	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")

This results in an error:

> invalid operation: `{"image": ` + data (mismatched types untyped string and []byte)`

the "data" variable at this point is []uint8 ([]byte). I realize, at a high level, what is wrong. I'm trying to join two data types that are not the same. That's about it though. I've tried a bunch of stuff that I'm pretty sure anyone familiar with Go would immediately realize was wrong (declaring jsonData as a byte, converting data to a string, using os.Open instead of ioutil.ReadFile, etc.). I'm just kind of stumbling around blind though. I can't find an example that doesn't use a plain string as the JSON data.

I would appreciate any thoughts.

--- ANSWER ---

I'm marking Dietrich Epp's answer as accepted, because he gave me what I asked for. However, RedBlue in the comments gave me what I actually needed. Thank you both. The code below is modified just a bit from this answer: https://stackoverflow.com/a/56696333/2707357

Change the url variable to your DeepStack server, and the file name to one that actually exists, and the response body should return the necessary information.

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
	}
	// Don't forget to set the content type, this will contain the boundary.
	req.Header.Set("Content-Type", w.FormDataContentType())

	client := &http.Client{}
	response, error := client.Do(req)
	if err != nil {
		panic(error)
	}
	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))
}

答案1

得分: -1

这只是一个非常小的错误。据我所知,你的问题归结为以下内容:

var data []byte // 有一些值
jsonData := []byte(`{"image": ` + data + `}`)

你只需要将其改为使用append()或类似的方法:

jsonData := append(
    append([]byte(`{"image": `), data...),
    '}')

原因是在Go语言中不能使用+来连接[]byte。不过你可以使用append()来实现。

英文:

It's really such a small error. This is all your question boils down to, as far as I can tell:

var data []byte // with some value
jsonData := []byte(`{"image": ` + data + `}`)

All you have to do is change this to use append() or something similar:

jsonData := append(
    append([]byte(`{"image": `), data...),
    '}')

The reason is that you can't use + to concatenate []byte in Go. You can use append(), though.

huangapple
  • 本文由 发表于 2022年6月24日 03:37:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/72735728.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定