【问题标题】:Go doing a GET request and building the Querystring去做一个 GET 请求并构建 Querystring
【发布时间】:2015-08-19 13:55:51
【问题描述】:

我对 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,它需要 api_key 的 GET 变量,并将您的 api 键作为值。问题在于这会以以下形式进行硬编码:

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

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

【问题讨论】:

  • 那么连接字符串有什么问题?
  • 我想什么都没有,但这并不是一个真正优雅的解决方案,只是认为在 Go 中有更好的做事方式。您会看到动作和方法的变化,然后您必须将所有内容串在一起。
  • 你可以使用url.ValuesEncode方法。您还可以使用URL.String 来构建整个 URL。

标签: http go


【解决方案1】:

正如评论者所说,您可以从 net/url 获得 Values,它有一个 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

【讨论】:

  • 太棒了,谢谢你!这正是我想要的!
  • 也非常适合测试!
  • @artificerpi 如果由于某种原因它很重要,您可以重新实现它们在 Encode 方法中所做的事情 golang.org/src/net/url/url.go?s=24222:24253#L845 但我想知道为什么它很重要。
  • 如果你不使用它,你就不需要使用 NewRequest。你可以直接使用url.Parse("https://something.com/"),甚至直接创建一个URL对象。
  • @JakeBoomgaarden http.NewRequest 函数实际上并不调用远程服务器。它只是构造一个*http.Request 变量供您使用。您可以根据自己的喜好调整请求,然后通过将其传递给 *http.Client.Do 方法将其发送出去。
【解决方案2】:

在附加到现有查询时使用r.URL.Query(),如果您正在构建新的参数集,请使用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
}

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 同意,很好的回答!
    • 这应该是公认的答案。
    猜你喜欢
    • 1970-01-01
    • 2013-11-02
    • 2014-05-12
    • 1970-01-01
    • 2016-12-16
    • 2019-07-07
    • 2012-10-21
    • 1970-01-01
    • 2013-08-30
    相关资源
    最近更新 更多