Golang 结构体作为 POST 请求的负载数据

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

Golang Struct as Payload for POST Request

问题

新手学习golang。我正在尝试向身份验证端点发出POST请求,以获取用于进一步身份验证的令牌。目前我得到的错误是missing "credentials"。我已经用Python编写了相同的逻辑,所以我知道我尝试做的是系统所期望的。

问题是-我是否正确地将AUTH结构编组为JSON,并适当地将其添加到POST请求中?由于API甚至没有在JSON中看到credentials键,我认为我一定做错了什么。任何帮助都可以。

英文:

New to golang. I'm trying to make a POST request to an auth endpoint to get back a token for authing further requests. Currently the error I'm getting is missing "credentials". I've written the same logic in Python so I know what I am trying to do is what the system is expecting.

package main

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

type Auth struct {
	Method   string `json:"credentials"`
	Email    string `json:"email"`
	Password string `json:"password"`
	Mfa      string `json:"mfa_token"`
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	fmt.Print("Enter Email: ")
	e, _ := reader.ReadString('\n')
	fmt.Print("Enter Password: ")
	p, _ := reader.ReadString('\n')
	fmt.Print("Enter 2FA Token: ")
	authy, _ := reader.ReadString('\n')

	auth := Auth{"manual", e, p, authy}
	j, _ := json.Marshal(auth)
	jar, _ := cookiejar.New(nil)
	client := &http.Client{
		Jar: jar,
	}

	req, err := http.NewRequest("POST", "https://internaltool.com/v3/sessions", bytes.NewBuffer(j))
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Add("Accept-Encoding", "gzip, deflate, br")
	res, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	body, _ := ioutil.ReadAll(res.Body)
	s := string(body)
	if res.StatusCode == 400 {
		fmt.Println("Bad Credentials")
		fmt.Println(s)
		return
	}
}

The question is - am I properly marshalling the AUTH struct into JSON and adding it appropriately to the POST request? As the API is not even seeing the credentials key in the JSON I think I must be doing something wrong. Anything helps.

答案1

得分: 13

这是一个使用json.Marshal的最小可行示例,将结构体转换为JSON对象,并在POST请求的上下文中使用。

Go的标准库非常出色,没有必要引入外部依赖来完成这样的琐事。

func TestPostRequest(t *testing.T) {

	// 创建一个Person的新实例
	person := Person{
		Name: "Ryan Alex Martin",
		Age:  27,
	}

	// 在发起请求之前将其编组为JSON
	personJSON, err := json.Marshal(person)

	// 使用编组后的JSON作为POST请求的主体进行请求
	resp, err := http.Post("https://httpbin.org/anything", "application/json",
		bytes.NewBuffer(personJSON))

	if err != nil {
		t.Error("无法向httpbin发起POST请求")
	}

	// 就是这样!

	// 但为了保险起见,让我们查看一下响应主体。
	body, err := ioutil.ReadAll(resp.Body)

	var result PersonResponse
	err = json.Unmarshal([]byte(body), &result)
	if err != nil {
		t.Error("从请求中解组数据时出错。")
	}

	if result.NestedPerson.Name != "Ryan Alex Martin" {
		t.Error("从服务器返回的名称字段不正确或为空:", result.NestedPerson.Name)
	}

	fmt.Println("来自服务器的响应:", result.NestedPerson.Name)
	fmt.Println("来自服务器的响应:", result.NestedPerson.Age)

}

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

// NestedPerson是响应的'json'字段,即我们最初发送到httpbin的Nested Person{}
type PersonResponse struct {
	NestedPerson Person `json:"json"` // 在'json'字段中的嵌套Person{}
}
英文:

Here's a minimum viable example of using json.Marshal to convert a Struct to a JSON object in the context of a POST request.

Go's standard libraries are fantastic, there is no need to pull in external dependencies to do such a mundane thing.

func TestPostRequest(t *testing.T) {

	// Create a new instance of Person
	person := Person{
		Name: "Ryan Alex Martin",
		Age:  27,
	}

	// Marshal it into JSON prior to requesting
	personJSON, err := json.Marshal(person)

	// Make request with marshalled JSON as the POST body
	resp, err := http.Post("https://httpbin.org/anything", "application/json",
		bytes.NewBuffer(personJSON))

	if err != nil {
		t.Error("Could not make POST request to httpbin")
	}

	// That's it!

	// But for good measure, let's look at the response body.
	body, err := ioutil.ReadAll(resp.Body)

	var result PersonResponse
	err = json.Unmarshal([]byte(body), &result)
	if err != nil {
		t.Error("Error unmarshaling data from request.")
	}

	if result.NestedPerson.Name != "Ryan Alex Martin" {
		t.Error("Incorrect or nil name field returned from server: ", result.NestedPerson.Name)
	}

	fmt.Println("Response from server:", result.NestedPerson.Name)
	fmt.Println("Response from server:", result.NestedPerson.Age)

}

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

// NestedPerson is the 'json' field of the response, what we originally sent to httpbin
type PersonResponse struct {
	NestedPerson Person `json:"json"` // Nested Person{} in 'json' field
}


答案2

得分: 0

作为一个相对较低级的抽象,强烈推荐使用gorequest(https://github.com/parnurzeal/gorequest)作为http.Client的替代方案。

可以以任何类型发布头部、查询和正文,这更像是我们在Python中经常做的事情。

英文:

As http.Client is relatively a low-level abstraction, gorequest(https://github.com/parnurzeal/gorequest) as an alternative is strongly recommended.

headers, queries, and body can be posted in any type, which is a bit more like what we often do in Python.

huangapple
  • 本文由 发表于 2017年8月1日 06:18:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/45426137.html
匿名

发表评论

匿名网友

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

确定