解析 POST 请求中的 req.body。

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

Parse req.body in POST request

问题

我正在使用fetch API将两个值发送到我的POST请求处理程序...

fetch('http://localhost:8080/validation', {
	method:'POST',
	headers: {
		'Accept': 'application/json',
		'Content-Type': 'application/json'
	},
	body: JSON.stringify({
		email:this.state.email,
		password:this.state.password
	})

我想将emailpassword都保存为服务器端的字符串。这是我的尝试...

type credentials struct {
    Test string
}

func Validate(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
   
    decoder := json.NewDecoder(req.Body)

    var creds credentials

    err := decoder.Decode(&creds)

    if err != nil {
        panic(err)
    }

    fmt.Println(creds.Test)
}

问题是我不知道要发送到POST的结构的确切格式。我试图将req.Body保存为字符串,但没有任何结果。

当我打印fmt.Println时,我得到一个空格。解析它的正确方法是什么?

英文:

I am using fetch API to send two values to my POST request handler...

fetch('http://localhost:8080/validation', {
		method:'POST',
		headers: {
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		body: JSON.stringify({
			email:this.state.email,
			password:this.state.password
		})

I want to save both email and password as strings on the server side. Here is my attempt...

type credentials struct {
    Test string
}

func Validate(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
   
    decoder := json.NewDecoder(req.Body)

    var creds credentials

    err := decoder.Decode(&creds)

    if err != nil {
	    panic(err)
    }

    fmt.Println(creds.Test)
}

The problem is I do not know how exactly the format of the structure being sent to the POST. I am attempting to save req.Body as a string but this yields nothing.

When I print fmt.Println I get a blank space. What is the proper way of parsing it?

答案1

得分: 5

尝试使用以下代码:

type credentials struct {
    Email    string `json:"email"`
    Password string `json:"password"`
}

您将收到一个包含两个值的 JSON。接收结构体应该具有与您的请求匹配的结构。否则,没有占位符可以将 JSON 解码为,就像您的情况一样 - 邮件和密码没有匹配的结构字段。顺便说一下,如果您在 JSON 中发送 "Test",这将起作用,因为您的结构中有一个 Test 字段!

关于字段名称。如果 JSON 中的字段不以大写字母开头,甚至具有不同的名称,那么您应该使用所谓的标签(tags)。
有关标签的更多信息:https://golang.org/pkg/encoding/json/#Marshal

在我的示例中,我使用它们将结构字段名称与您的 JSON 字段匹配,即使将 JSON 中的 "email" 匹配到 "credentials" 结构体的 "Email" 字段。

英文:

Try with

type credentials struct {
    Email string `json:"email"`
    Password string `json:"password"`
}

You are receiving a JSON with two values. Receiving struct should have a structure matching your request. Otherwise, there are no placeholders to decode the JSON into, as in your case - email and password do not have matching struct fields. Btw. if you send "Test" in your JSON, this would work, as you have a Test field in your struct!

Regarding field names. If fields in JSON do not start with a capital letter or even have different names, then you should use so called tags.
More on tags: https://golang.org/pkg/encoding/json/#Marshal

In my example I used them to match struct field names to your json fields, i.e. to make email from json match Email field of the credentials struct.

答案2

得分: 2

req.Body 是一个 io.Reader,你可以使用 ioutil.ReadAll 来读取它:

data, err := ioutil.ReadAll(req.Body)
asString := string(data) // 你可以通过类型转换将其转换为字符串

但我不确定你是否想要将 req.Body 保存为字符串。

要将响应解析为数据结构,你可以将其解组为类型为 *interface{} 的变量:

var creds interface{}
decoder.Decode(&creds)

然后检查该值:

fmt.Printf("%#v\n", creds)

或者你可以使用 pp.Println(creds),我觉得这样更容易阅读。

creds 变量将表示在请求体中找到的 JSON 对象,对于你的示例输入,它将是一个 map[string]interface{},其中包含两个条目,可能都是字符串。类似于:

map[string]interface{}{
    "email": email_value,
    "password": password_value,
}

你可以使用以下代码检查这些值:

email, ok := creds["email"].(string)
if ok {
    // email 将包含该值,因为 creds["email"] 通过了类型检查
    fmt.Printf("submitted email is %#v\n", email)
} else {
    // "email" 属性是一个字符串(可能缺失,也可能是其他类型)
}

json.Unmarshal 的文档 在关于解组为接口值的讨论中解释了如何解析任意 JSON 字符串而不事先知道其结构的语义。

英文:

req.Body is an io.Reader, and you can get use ioutil.ReadAll to drain it:

data, err := ioutil.ReadAll(req.Body)
asString := string(data) // you can convert to a string with a typecast

But I'm not sure if that's what you meant by trying to save req.Body as a string.

To parse the response into a data structure, you can unmarshal it into a variable of type *interface{}:

var creds interface{}
decoder.Decode(&creds)

And then examine the value:

fmt.Printf("%#v\n", creds)

Or perhaps using pp.Println(creds) which I find easier to read.

The creds variable will represent the JSON object found in the body, for your example input this will be a map[string]interface{} with two entries, presumably both of them strings. Something like:

map[string]interface{}{
    "email": email_value,
    "password": password_value,
}

and you check the values with:

email, ok := creds["email"].(string)
if ok {
    // email will contain the value because creds["email"] passed the type check
    fmt.Printf("submitted email is %#v\n", email)
} else {
    // "email" property was a string (may be missing, may be something else)
}

The documentation of json.Unmarshal explains the semantics of how arbitrary JSON strings can be parsed without knowing their structure in advance in the discussion about unmarshalling to interface values.

huangapple
  • 本文由 发表于 2016年12月17日 13:18:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/41195596.html
匿名

发表评论

匿名网友

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

确定