Führen Sie eine GET-Anforderung aus und erstellen Sie den Querystring

85

Ich bin ziemlich neu in Go und verstehe noch nicht alles. In vielen der modernen Sprachen Node.js, Angular, jQuery, PHP können Sie eine GET-Anforderung mit zusätzlichen Abfragezeichenfolgenparametern ausführen.

Dies in Go zu tun ist nicht ganz einfach, wie es scheint, und ich kann es noch nicht wirklich herausfinden. Ich möchte wirklich nicht für jede der Anforderungen, die ich ausführen möchte, eine Zeichenfolge verketten müssen.

Hier ist das Beispielskript:

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

In diesem Beispiel sehen Sie, dass es eine URL gibt, für die eine GET-Variable von api_key mit Ihrem API-Schlüssel als Wert erforderlich ist. Das Problem besteht darin, dass dies in Form von:

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

Gibt es eine Möglichkeit, diese Abfragezeichenfolge dynamisch zu erstellen? Im Moment muss ich die URL vor diesem Schritt zusammenstellen, um eine gültige Antwort zu erhalten.

Rudi Strydom
quelle
1
Was ist also falsch daran, eine Zeichenfolge zu verketten?
Salvador Dali
4
Ich nehme an, nichts, aber es ist nicht wirklich eine elegante Lösung, ich dachte nur, es gibt eine bessere Möglichkeit, Dinge in Go zu tun. Sie sehen die Aktionsänderungen, die Methode und dann müssen Sie alles aneinander reihen.
Rudi Strydom
2
Sie können mit url.Values‚s - EncodeMethode. Sie können auch URL.Stringdie gesamte URL erstellen.
Dave C

Antworten:

208

Wie ein Kommentator erwähnte, kann man Valuesvon net/urlwelcher EncodeMethode eine bekommen. Sie könnten so etwas tun ( req.URL.Query()gibt das vorhandene zurück 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

jcbwlkr
quelle
1
Super danke Mann! Genau das habe ich gesucht!
Rudi Strydom
Ideal auch zum Testen!
Kyle Chadha
Gibt es eine Lösung, um die Parameter der Abfragezeichenfolge in der gewünschten Reihenfolge festzulegen? Die Schlüssel sind nach Encode()Methoden sortiert .
Artificerpi
1
@artificerpi Wenn es aus irgendeinem Grund kritisch war, könnten Sie neu implementieren, was sie in der Encode-Methode tun. golang.org/src/net/url/url.go?s=24222:24253#L845 Aber ich würde mich fragen, warum es wichtig ist.
jcbwlkr
3
Sie müssen NewRequest nicht verwenden, wenn Sie nichts damit anfangen. Sie können url.Parse("https://something.com/")stattdessen einfach ein URL-Objekt verwenden oder sogar direkt erstellen.
Richard
34

Verwenden r.URL.Query()Sie diese Option, wenn Sie an eine vorhandene Abfrage anhängen. Wenn Sie einen neuen Satz von Parametern erstellen, verwenden Sie die url.ValuesStruktur wie folgt

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
}
Allyraza
quelle
11

Mit Hilfe NewRequesteiner URL zu erstellen , ist zuviel des Guten. Verwenden Sie das net/urlPaket:

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

Spielplatz: https://play.golang.org/p/YCTvdluws-r

Janek Olszak
quelle
einfachste Antwort und hat perfekt funktioniert, danke
Jake Boomgaarden