去做一个GET请求并建立查询字符串


85

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

在此示例中,您可以看到一个URL,该URL要求api_key的GET变量为api键作为值。问题在于,这变成了以下形式的硬编码:

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

有没有一种方法可以动态构建此查询字符串?此刻,我需要在此步骤之前组装URL,以获得有效的响应。


1
那么连接字符串有什么问题呢?
萨尔瓦多·达利

4
我想什么都没有,但这并不是真正的优雅解决方案,只是认为Go中有更好的做事方法。您将看到操作发生变化,方法发生变化,然后您必须将所有内容串在一起。
Rudi Strydom 2015年

2
您可以使用url.ValuesEncode方法。您还可以URL.String用来构建整个URL。
Dave C

Answers:


208

作为一个评论者提到你可以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
}

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


1
太棒了,谢谢你!那正是我想要的!
Rudi Strydom

也非常适合测试!
凯尔·查达

有什么解决方案可以使查询字符串参数按需要的顺序排列?键按Encode()方法排序。
artificerpi

1
@artificerpi如果由于某种原因很关键,您可以在Encode方法中重新实现它们的功能golang.org/src/net/url/url.go?s=24222:24253#L845但是我想知道为什么这很重要。
jcbwlkr

3
如果您不对其进行任何操作,则无需使用NewRequest。您可以url.Parse("https://something.com/")改用甚至直接创建URL对象。
理查德

34

使用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
}

11

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

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


最简单的答案,很完美的工作,谢谢
杰克·鲍姆加登
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.