How do I send a JSON string in a POST request in Go

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

How do I send a JSON string in a POST request in Go

问题

我尝试使用Apiary并创建了一个通用模板来向模拟服务器发送JSON,并有以下代码:

package main

import (
	"encoding/json"
	"fmt"
	"github.com/jmcvetta/napping"
	"log"
	"net/http"
)

func main() {
	url := "http://restapi3.apiary.io/notes"
	fmt.Println("URL:>", url)

	s := napping.Session{}
	h := &http.Header{}
	h.Set("X-Custom-Header", "myvalue")
	s.Header = h

	var jsonStr = []byte(`
{
    "title": "Buy cheese and bread for breakfast."
}`)

	var data map[string]json.RawMessage
	err := json.Unmarshal(jsonStr, &data)
	if err != nil {
		fmt.Println(err)
	}

	resp, err := s.Post(url, &data, nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("response Status:", resp.Status())
	fmt.Println("response Headers:", resp.HttpResponse().Header)
	fmt.Println("response Body:", resp.RawText())

}

这段代码无法正确发送JSON,但我不知道原因。每次调用时,JSON字符串可能会有所不同。我不能使用Struct来解决这个问题。

英文:

I tried working with Apiary and made a universal template to send JSON to mock server and have this code:

package main

import (
	"encoding/json"
	"fmt"
	"github.com/jmcvetta/napping"
	"log"
	"net/http"
)

func main() {
	url := "http://restapi3.apiary.io/notes"
	fmt.Println("URL:>", url)

	s := napping.Session{}
	h := &http.Header{}
	h.Set("X-Custom-Header", "myvalue")
	s.Header = h

	var jsonStr = []byte(`
{
    "title": "Buy cheese and bread for breakfast."
}`)

	var data map[string]json.RawMessage
	err := json.Unmarshal(jsonStr, &data)
	if err != nil {
		fmt.Println(err)
	}

	resp, err := s.Post(url, &data, nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("response Status:", resp.Status())
	fmt.Println("response Headers:", resp.HttpResponse().Header)
	fmt.Println("response Body:", resp.RawText())

}

This code doesn't send JSON properly, but I don't know why. The JSON string can be different in every call. I can't use Struct for this.

答案1

得分: 700

我不熟悉小睡,但是使用Golang的net/http包可以正常工作(playground):

func main() {
    url := "http://restapi3.apiary.io/notes"
    fmt.Println("URL:>", url)

    var jsonStr = []byte(`{"title":"Buy cheese and bread for breakfast."}`)
    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
    req.Header.Set("X-Custom-Header", "myvalue")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("response Status:", resp.Status)
    fmt.Println("response Headers:", resp.Header)
    body, _ := io.ReadAll(resp.Body)
    fmt.Println("response Body:", string(body))
}
英文:

I'm not familiar with napping, but using Golang's net/http package works fine (playground):

func main() {
	url := "http://restapi3.apiary.io/notes"
	fmt.Println("URL:>", url)

	var jsonStr = []byte(`{"title":"Buy cheese and bread for breakfast."}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))
}

答案2

得分: 170

你可以使用post方法来发送你的JSON数据。

values := map[string]string{"username": username, "password": password}

jsonValue, _ := json.Marshal(values)

resp, err := http.Post(authAuthenticatorUrl, "application/json", bytes.NewBuffer(jsonValue))

请注意,以上代码是用Go语言编写的。

英文:

you can just use post to post your json.

values := map[string]string{"username": username, "password": password}

jsonValue, _ := json.Marshal(values)

resp, err := http.Post(authAuthenticatorUrl, "application/json", bytes.NewBuffer(jsonValue))

答案3

得分: 48

如果您已经有一个结构体。

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"os"
)

// .....

type Student struct {
	Name    string `json:"name"`
	Address string `json:"address"`
}

// .....

body := &Student{
	Name:    "abc",
	Address: "xyz",
}

payloadBuf := new(bytes.Buffer)
json.NewEncoder(payloadBuf).Encode(body)
req, _ := http.NewRequest("POST", url, payloadBuf)

client := &http.Client{}
res, e := client.Do(req)
if e != nil {
	return e
}

defer res.Body.Close()

fmt.Println("response Status:", res.Status)
// 将响应体打印到标准输出
io.Copy(os.Stdout, res.Body)

完整的gist

英文:

If you already have a struct.

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"os"
)

// .....

type Student struct {
	Name    string `json:"name"`
	Address string `json:"address"`
}

// .....

body := &Student{
	Name:    "abc",
	Address: "xyz",
}

payloadBuf := new(bytes.Buffer)
json.NewEncoder(payloadBuf).Encode(body)
req, _ := http.NewRequest("POST", url, payloadBuf)

client := &http.Client{}
res, e := client.Do(req)
if e != nil {
	return e
}

defer res.Body.Close()

fmt.Println("response Status:", res.Status)
// Print the body to the stdout
io.Copy(os.Stdout, res.Body)

Full gist.

答案4

得分: 14

除了标准的net/http包,你可以考虑使用我的GoRequest,它封装了net/http,让你的生活更轻松,不需要过多考虑json或结构体。但你也可以在一个请求中混合使用它们!(你可以在gorequest的GitHub页面上了解更多详细信息)

所以,最终你的代码将变成如下所示:

func main() {
    url := "http://restapi3.apiary.io/notes"
    fmt.Println("URL:>", url)
    request := gorequest.New()
    titleList := []string{"title1", "title2", "title3"}
    for _, title := range titleList {
        resp, body, errs := request.Post(url).
            Set("X-Custom-Header", "myvalue").
            Send(`{"title":"` + title + `"}`).
            End()
        if errs != nil {
            fmt.Println(errs)
            os.Exit(1)
        }
        fmt.Println("response Status:", resp.Status)
        fmt.Println("response Headers:", resp.Header)
        fmt.Println("response Body:", body)
    }
}

这取决于你想要实现的方式。我创建这个库是因为我和你有同样的问题,我希望代码更短、更容易使用json,并且在我的代码库和生产系统中更易于维护。

英文:

In addition to standard net/http package, you can consider using my GoRequest which wraps around net/http and make your life easier without thinking too much about json or struct. But you can also mix and match both of them in one request! (you can see more details about it in gorequest github page)

So, in the end your code will become like follow:

func main() {
	url := "http://restapi3.apiary.io/notes"
	fmt.Println("URL:>", url)
	request := gorequest.New()
	titleList := []string{"title1", "title2", "title3"}
	for _, title := range titleList {
		resp, body, errs := request.Post(url).
			Set("X-Custom-Header", "myvalue").
			Send(`{"title":"` + title + `"}`).
			End()
		if errs != nil {
			fmt.Println(errs)
			os.Exit(1)
		}
		fmt.Println("response Status:", resp.Status)
		fmt.Println("response Headers:", resp.Header)
		fmt.Println("response Body:", body)
	}
}

This depends on how you want to achieve. I made this library because I have the same problem with you and I want code that is shorter, easy to use with json, and more maintainable in my codebase and production system.

答案5

得分: 6

示例的HTTP或HTTPS的POST请求如下:

//编码数据
postBody, _ := json.Marshal(map[string]string{
   "name":  "Test",
   "email": "Test@Test.com",
})
responseBody := bytes.NewBuffer(postBody)

//利用Go的HTTP Post函数发送请求
resp, err := http.Post("https://postman-echo.com/post", "application/json", responseBody)

//处理错误
if err != nil {
   log.Fatalf("发生错误:%v", err)
}
defer resp.Body.Close()

//读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
   log.Fatalln(err)
}
sb := string(body)
log.Printf(sb)

以上是一个使用Go语言发送HTTP或HTTPS的POST请求的示例代码。

英文:

Example post request for http or https

    //Encode the data
       postBody, _ := json.Marshal(map[string]string{
          "name":  "Test",
          "email": "Test@Test.com",
       })
       responseBody := bytes.NewBuffer(postBody)
    //Leverage Go's HTTP Post function to make request
       resp, err := http.Post("https://postman-echo.com/post", "application/json", responseBody)
    //Handle Error
       if err != nil {
          log.Fatalf("An Error Occured %v", err)
       }
       defer resp.Body.Close()
    //Read the response body
       body, err := ioutil.ReadAll(resp.Body)
       if err != nil {
          log.Fatalln(err)
       }
       sb := string(body)
       log.Printf(sb)

答案6

得分: 5

使用io.Pipe来处理大型请求体,如另一个答案中所提到的。这种方法通过将数据从JSON编码器流式传输到网络,避免了在内存中构建整个请求体。

这个答案在另一个答案的基础上展示了如何处理错误。始终要处理错误!

  • 使用pipe的CloseWithError函数将编码错误传播回从http.Post返回的错误。
  • 处理从http.Post返回的错误。
  • 关闭响应体。

以下是代码示例:

r, w := io.Pipe()

go func() {
    w.CloseWithError(json.NewEncoder(w).Encode(data))
}()

// 确保管道的读取端被关闭。这样做是为了在http.Post在读取完整个请求体之前出错的情况下解除阻塞的goroutine。
defer r.Close()

resp, err := http.Post(url, r)
if err != nil {
    // 根据应用程序的要求调整错误处理。
    log.Fatal(err)
}
defer resp.Body.Close()
// 在这里使用响应。

希望对你有帮助!

英文:

Use io.Pipe for large request bodies as mentioned in another answer. This approach avoids building the entire request body in memory by streaming the data from the JSON encoder to the network.

This answer builds on the other answer by showing how to handle errors. Always handle errors!

  • Use the pipe's CloseWithError function to propagate encoding errors back to error returned from http.Post.
  • Handle the error returned from http.Post
  • Close the response body.

Here's the code:

r, w := io.Pipe()

go func() {
	w.CloseWithError(json.NewEncoder(w).Encode(data))
}()

// Ensure that read side of pipe is closed. This
// unblocks goroutine in scenario where http.Post
// errors out before reading the entire request body.
defer r.Close()

resp, err := http.Post(url, r)
if err != nil {
	// Adjust error handling here to meet application requrirements.
	log.Fatal(err)
}
defer resp.Body.Close()
// Use the response here.

答案7

得分: 3

如果你有大量的数据要发送,你可以使用管道(pipe):

package main

import (
   "encoding/json"
   "io"
   "net/http"
)

func main() {
   m := map[string]int{"SNG_ID": 75498415}
   r, w := io.Pipe()
   go func() {
      json.NewEncoder(w).Encode(m)
      w.Close()
   }()
   http.Post("https://stackoverflow.com", "application/json", r)
}

更多信息请参考:https://golang.org/pkg/io#Pipe

英文:

If you have a lot of data to send, you can use a pipe:

package main

import (
   "encoding/json"
   "io"
   "net/http"
)

func main() {
   m := map[string]int{"SNG_ID": 75498415}
   r, w := io.Pipe()
   go func() {
      json.NewEncoder(w).Encode(m)
      w.Close()
   }()
   http.Post("https://stackoverflow.com", "application/json", r)
}

https://golang.org/pkg/io#Pipe

答案8

得分: 2

我会使用net/http包而不是napping

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	url := "http://restapi3.apiary.io/notes"
	fmt.Println("URL:>", url)

	client := &http.Client{}

	var jsonStr = []byte(`
{
	"title": "买奶酪和面包作为早餐。"
}`)

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	if err != nil {
		log.Fatal(err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Custom-Header", "myvalue")

	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("response Body:", string(body))
}

这将使用JSON数据作为请求体创建一个新的POST请求,设置必要的头部,并使用http.Client发送请求。

替换占位符

英文:

I would use net/http package instead of the napping.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	url := "http://restapi3.apiary.io/notes"
	fmt.Println("URL:>", url)

	client := &http.Client{}

	var jsonStr = []byte(`
{
	"title": "Buy cheese and bread for breakfast."
}`)

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	if err != nil {
		log.Fatal(err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Custom-Header", "myvalue")

	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("response Body:", string(body))
}

This creates a new POST request with the JSON data as the request body, sets the necessary headers, and sends the request using an http.Client.

  • replace placeholders*.

答案9

得分: 1

如果你想这样做,你需要使用这个映射来解析 JSON 字符串。

var data map[string]interface{}

但是,如果你需要每次更改 JSON 并且使请求体的初始化更加方便,你可以使用这个映射来创建 JSON 请求体。

var bodyJsonMap map[string]interface{}{
    "key1": val1,
    "key2": val2,
    ...
}

然后将其编组为 JSON 字符串。

英文:

if you want to do it like that, you need to use this map for unmarshalling json string.

var data map[string]interface{}

but if you need to change the json each time and to make initialization of your requst body more convenient, you can use this map for creating json body.

var bodyJsonMap map[string]interface{}{
    "key1": val1,
    "key2": val2,
    ...
}

Then marshal it to a json-string.

huangapple
  • 本文由 发表于 2014年6月27日 23:09:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/24455147.html
匿名

发表评论

匿名网友

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

确定