Thực hiện yêu cầu ĐĂNG được mã hóa URL bằng cách sử dụng `http.NewRequest (…) '


96

Tôi muốn thực hiện một yêu cầu ĐĂNG tới một API gửi dữ liệu của tôi dưới dạng một application/x-www-form-urlencodedloại nội dung. Do thực tế là tôi cần quản lý các tiêu đề yêu cầu, tôi đang sử dụng http.NewRequest(method, urlStr string, body io.Reader)phương pháp này để tạo một yêu cầu. Đối với yêu cầu ĐĂNG này, tôi nối truy vấn dữ liệu của mình vào URL và để trống phần nội dung, giống như sau:

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

Khi tôi trả lời, tôi luôn nhận được một 400 BAD REQUEST. Tôi tin rằng vấn đề phụ thuộc vào yêu cầu của tôi và API không hiểu tôi đang đăng tải trọng nào. Mặc dù vậy, tôi biết các phương pháp như Request.ParseForm, nhưng không thực sự chắc chắn về cách sử dụng nó trong bối cảnh này. Có lẽ tôi đang thiếu một số Header khác, có thể có cách nào tốt hơn để gửi tải trọng dưới dạng một application/jsonloại sử dụng bodytham số?

Câu trả lời:


184

Trọng tải được mã hóa URL phải được cung cấp trên bodytham số của http.NewRequest(method, urlStr string, body io.Reader)phương thức, như một loại triển khai io.Readergiao diện.

Dựa trên mã mẫu:

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.Status200 OKcách này.


2
Nếu tôi không muốn gửi bất kỳ dữ liệu nào thì sao ?? Nếu tôi gửi bất kỳ dữ liệu giả nào thay cho `byte.NewBufferString (data.Encode ())`, nó có hoạt động không?
Aditya Peshave

Tôi muốn gửi một * Bộ đệm trống: ví dụ: đã bchovar b bytes.Buffer
Fernando Á.

4
Bạn không cần phải đặt Content-Lenghttiêu đề, cũng như http.NewRequestvậy.
dvdplm

12
Tôi nghĩ chúng ta có thể sử dụng strings.NewReader(data.Encode())(hiệu quả hơn) thay vì bytes.NewBufferString(data.Encode()). Tại func NewReader (s string) * Reader , nó cho biết "NewReader trả về một lần đọc Reader mới từ s. Nó tương tự như byte.NewBufferString nhưng hiệu quả hơn và chỉ đọc."
Liyang Chen

1
data.Setnên được sử dụng cho cả hai namesurname, thay vì data.Add. Nó đặt giá trị của khóa, thay vì nối một giá trị khác vào cùng một khóa, như data.Addvậy. Addcũng hoạt động, nhưng không cần thiết append(v[key], value)để làm trống lát.
metalim
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.