去做一个GET请求并构建Querystring

Rud*_*dom 57 http go

我是Go的新手,还不太了解一切.在许多现代语言Node.js,Angular,jQuery,PHP中,您可以使用其他查询字符串参数执行GET请求.

在Go中执行此操作并不像看起来那么简单,我还不能真正弄清楚它.我真的不想为我想要做的每个请求连接一个字符串.

以下是示例脚本:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    client := &http.Client{}

    req, _ := http.NewRequest("GET", "http://api.themoviedb.org/3/tv/popular", nil)
    req.Header.Add("Accept", "application/json")
    resp, err := client.Do(req)

    if err != nil {
        fmt.Println("Errored when sending request to the server")
        return
    }

    defer resp.Body.Close()
    resp_body, _ := ioutil.ReadAll(resp.Body)

    fmt.Println(resp.Status)
    fmt.Println(string(resp_body))
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,你可以看到有一个URL,它需要一个api_key的GET变量,你的api键作为值.问题在于它变成了以下形式的硬编码:

req, _ := http.NewRequest("GET", "http://api.themoviedb.org/3/tv/popular?api_key=mySuperAwesomeApiKey", nil)
Run Code Online (Sandbox Code Playgroud)

有没有办法动态构建这个查询字符串?目前,我需要在此步骤之前组合URL,以获得有效的响应.

jcb*_*lkr 159

作为一个评论者提到你可以Valuesnet/url它有一个Encode方法.你可以这样做(req.URL.Query()返回现有的url.Values)

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    req, err := http.NewRequest("GET", "http://api.themoviedb.org/3/tv/popular", nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }

    q := req.URL.Query()
    q.Add("api_key", "key_from_environment_or_flag")
    q.Add("another_thing", "foo & bar")
    req.URL.RawQuery = q.Encode()

    fmt.Println(req.URL.String())
    // Output:
    // http://api.themoviedb.org/3/tv/popular?another_thing=foo+%26+bar&api_key=key_from_environment_or_flag
}
Run Code Online (Sandbox Code Playgroud)

http://play.golang.org/p/L5XCrw9VIG

  • 如果您不使用 NewRequest,则不需要使用它。您可以只使用 `url.Parse("https://something.com/")` 代替,甚至可以直接创建一个 URL 对象。 (4认同)
  • @JakeBoomgaarden `http.NewRequest` 函数实际上并不调用远程服务器。它只是构造一个“*http.Request”变量供您使用。您可以根据自己的喜好调整请求,然后将其传递给“*http.Client.Do”方法来发送。 (3认同)
  • 厉害了谢谢大佬!这正是我要找的! (2认同)

Jan*_*zak 27

使用NewRequest刚刚创建的URL是矫枉过正。使用net/url包:

package main

import (
    "fmt"
    "net/url"
)

func main() {
    base, err := url.Parse("http://www.example.com")
    if err != nil {
        return
    }

    // Path params
    base.Path += "this will get automatically encoded"

    // Query params
    params := url.Values{}
    params.Add("q", "this will get encoded as well")
    base.RawQuery = params.Encode() 

    fmt.Printf("Encoded URL is %q\n", base.String())
}
Run Code Online (Sandbox Code Playgroud)

游乐场:https : //play.golang.org/p/YCTvdluws-r

  • 这确实应该是公认的答案。 (2认同)

小智 23

使用r.URL.Query()时,将追加到现有的查询,如果您正在构建新的一组则params的使用url.Values结构,像这样

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/url"
    "os"
)

func main() {
    req, err := http.NewRequest("GET","http://api.themoviedb.org/3/tv/popular", nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }

    // if you appending to existing query this works fine 
    q := req.URL.Query()
    q.Add("api_key", "key_from_environment_or_flag")
    q.Add("another_thing", "foo & bar")

    // or you can create new url.Values struct and encode that like so
    q := url.Values{}
    q.Add("api_key", "key_from_environment_or_flag")
    q.Add("another_thing", "foo & bar")

    req.URL.RawQuery = q.Encode()

    fmt.Println(req.URL.String())
    // Output:
    // http://api.themoviedb.org/3/tv/popularanother_thing=foo+%26+bar&api_key=key_from_environment_or_flag
}
Run Code Online (Sandbox Code Playgroud)