`http.NewRequest(…)`を使用してURLエンコードされたPOSTリクエストを作成します


94

データを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)
}

応答すると、常にが返され400 BAD REQUESTます。問題は私のリクエストに依存しており、APIは投稿しているペイロードを理解していません。私はのような方法を知っRequest.ParseFormていますが、このコンテキストでそれをどのように使用するかは本当にわかりません。多分私はいくつかの追加のヘッダーが欠落していますか、おそらくパラメーターapplication/jsonを使用してタイプとしてペイロードを送信するより良い方法はありbodyますか?

回答:


182

URLエンコードされたペイロードbodyは、インターフェースhttp.NewRequest(method, urlStr string, body io.Reader)を実装するタイプとして、メソッドのパラメーターで提供する必要があり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(http.MethodPost, 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)
}

resp.Statusである200 OKこの方法。


2
データを送信したくない場合はどうなりますか?`bytes.NewBufferString(data.Encode())`の代わりにダミーデータを送信すると、機能しますか?
Aditya Peshave

私は空の* Bufferを送信しようとします:たとえば、b与えられたvar b bytes.Buffer
FernandoÁ。

4
すでに設定されているように、Content-Lenghtヘッダーを設定する必要はありませんhttp.NewRequest
dvdplm 2015年

12
strings.NewReader(data.Encode())代わりに(より効率的に)使用できると思いますbytes.NewBufferString(data.Encode())。で、FUNC NewReader(S列)*リーダーは、それが「NewReaderはsから読ん新しいリーダーを返します。これは、bytes.NewBufferStringに似ていますが、より効率的で、読み取り専用です。」と言います
Liyang Chen

1
data.Setの代わりに、nameとの両方に使用する必要がsurnameありdata.Addます。同じキーに別の値を追加するのではなく、キーの値を設定しますdata.AddAdd動作しますが、append(v[key], value)スライスを空にする必要はありません。
メタリム2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.