Wykonaj żądanie GET i zbuduj Querystring


85

Jestem całkiem nowy w Go i jeszcze nie do końca wszystko rozumiem. W wielu współczesnych językach Node.js, Angular, jQuery, PHP można wykonać żądanie GET z dodatkowymi parametrami ciągu zapytania.

Robienie tego w Go nie jest takie proste, jak się wydaje, i nie mogę jeszcze tego rozgryźć. Naprawdę nie chcę łączyć łańcucha dla każdego żądania, które chcę wykonać.

Oto przykładowy skrypt:

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

W tym przykładzie widać, że istnieje adres URL, który wymaga zmiennej GET api_key z kluczem api jako wartością. Problem polega na tym, że zostaje to zakodowane w postaci:

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

Czy istnieje sposób dynamicznego tworzenia tego ciągu zapytania? W tej chwili będę musiał zebrać adres URL przed tym krokiem, aby uzyskać prawidłową odpowiedź.


1
Więc co jest złego w konkatenacji łańcucha?
— Salvador Dali

4
Przypuszczam, że nic, ale tak naprawdę nie jest to eleganckie rozwiązanie, po prostu pomyślałem, że istnieje lepszy sposób robienia rzeczy w Go. Widzisz, jak zmienia się akcja, metoda, a potem musisz wszystko połączyć.
— Rudi Strydom

2
Możesz użyć metody url.Values'' Encode. Możesz również użyć URL.Stringdo zbudowania całego adresu URL.
— Dave C

Odpowiedzi:


208

Jak wspomniał komentator, możesz uzyskać, Valuesz net/urlktórego ma Encodemetodę. Możesz zrobić coś takiego ( req.URL.Query()zwraca istniejący 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
Wspaniale dziękuję człowieku! Właśnie tego szukałem!
— Rudi Strydom

Świetne również do testowania!
— Kyle Chadha

Jakieś rozwiązanie, dzięki któremu parametry ciągu zapytania będą miały pożądaną kolejność? Klucze są posortowane według Encode()metody.
— artificerpi

1
@artificerpi, jeśli z jakiegoś powodu było to krytyczne, możesz ponownie zaimplementować to, co robią, w metodzie Encode golang.org/src/net/url/url.go?s=24222:24253#L845 .
— jcbwlkr

3
Nie musisz używać NewRequest, jeśli nic z nim nie robisz. Możesz po prostu użyć url.Parse("https://something.com/")zamiast tego lub nawet bezpośrednio utworzyć obiekt URL.
— Richard

34

Użyj r.URL.Query()podczas dołączania do istniejącego zapytania, jeśli budujesz nowy zestaw parametrów, użyj url.Valuesstruktury w ten sposób

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
}

12

Używanie NewRequestsamego tylko do tworzenia adresu URL to przesada. Skorzystaj z net/urlpakietu:

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

Plac zabaw: https://play.golang.org/p/YCTvdluws-r


najprostsza odpowiedź i działała idealnie, dzięki
— Jake Boomgaarden
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.