使用`http.NewRequest(...)`创建一个URL编码的POST请求

Fer*_* Á. 85 http go

我想对发送我的数据作为application/x-www-form-urlencoded内容类型的API发出POST请求.由于我需要管理请求标头,我正在使用该http.NewRequest(method, urlStr string, body io.Reader)方法来创建请求.对于此POST请求,我将我的数据查询附加到URL并将正文保留为空,如下所示:

package main

import (
    "bytes"
    "fmt"
    "net/http"
    "net/url"
    "strconv"
)

func main() {
    apiUrl := "https://api.com"
    resource := "/user/"
    data := url.Values{}
    data.Set("name", "foo")
    data.Add("surname", "bar")

    u, _ := url.ParseRequestURI(apiUrl)
    u.Path = resource
    u.RawQuery = data.Encode()
    urlStr := fmt.Sprintf("%v", u) // "https://api.com/user/?name=foo&surname=bar"

    client := &http.Client{}
    r, _ := http.NewRequest("POST", urlStr, nil)
    r.Header.Add("Authorization", "auth_token=\"XXXXXXX\"")
    r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))

    resp, _ := client.Do(r)
    fmt.Println(resp.Status)
}
Run Code Online (Sandbox Code Playgroud)

当我回答时,我总是得到一个400 BAD REQUEST.我相信问题依赖于我的请求,API不了解我发布的有效负载.我知道方法Request.ParseForm,但不确定如何在这种情况下使用它.也许我错过了一些更多的Header,也许是否有更好的方法application/json使用body参数发送有效负载?

Fer*_* Á. 158

必须bodyhttp.NewRequest(method, urlStr string, body io.Reader)方法的参数上提供URL编码的有效负载,作为实现io.Reader接口的类型.

基于示例代码:

package main

import (
    "fmt"
    "net/http"
    "net/url"
    "strconv"
    "strings"
)

func main() {
    apiUrl := "https://api.com"
    resource := "/user/"
    data := url.Values{}
    data.Set("name", "foo")
    data.Set("surname", "bar")

    u, _ := url.ParseRequestURI(apiUrl)
    u.Path = resource
    urlStr := u.String() // "https://api.com/user/"

    client := &http.Client{}
    r, _ := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode())) // URL-encoded payload
    r.Header.Add("Authorization", "auth_token=\"XXXXXXX\"")
    r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))

    resp, _ := client.Do(r)
    fmt.Println(resp.Status)
}
Run Code Online (Sandbox Code Playgroud)

resp.Status200 OK这样的.

  • 我想我们可以用`strings.NewReader(data.Encode())`(更有效),而不是`bytes.NewBufferString(data.Encode())`.在[func NewReader(s string)*Reader](https://golang.org/pkg/strings/#NewReader)中,它说"NewReader从s返回一个新的Reader读取.它类似于bytes.NewBufferString但效率更高和只读." (10认同)
  • 如果我不想发送任何数据怎么办?如果我发送任何虚拟数据代替 `bytes.NewBufferString(data.Encode())`,它会起作用吗? (4认同)
  • 您不需要设置Content-Lenght标头,因为http.NewRequest已经做到了。 (2认同)
  • “name”和“surname”都应使用“data.Set”,而不是“data.Add”。它设置键的值,而不是像“data.Add”那样将另一个值附加到同一个键。`Add` 也可以工作,但是会不必要的 `append(v[key], value)` 到空切片。 (2认同)