使用Golang结构体作为POST请求的有效载荷

10

我是新手Golang。 我正在尝试向认证终端点发送POST请求,以获取用于进一步验证请求的令牌。 目前我收到的错误是missing "credentials"。 我已经在Python中编写了相同的逻辑,因此我知道我正在尝试做的就是系统所期望的。

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
    }
}

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


3
也许您需要显式设置Content-Type,例如通过req.Header.Set("Content-Type", "application/json")。尝试检查和比较使用PythonGo实现的请求。可以使用类似于HTTP Fiddlerbetwixt的工具。 - putu
4
另外,不要忽略错误。你现在正在忽略json.Marshalcookiejar.Newioutil.ReadAll的错误。当你在解决问题时,你需要尽可能多的信息,而丢弃错误会丢掉潜在有价值的故障排除细节。 - Adrian
使用Wireshark检查发送了什么。 - hookenz
2个回答

13
这是使用 json.Marshal 的最小可行例子,它可以将一个结构体转换为JSON对象,并在POST请求的上下文中使用。
Go的标准库非常出色,没有必要引入外部依赖来完成这样一个平凡的任务。
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
}



0

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

头部、查询和正文可以以任何类型进行发布,这有点类似于我们在 Python 中经常做的事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接