Vai a fare una richiesta GET e costruire la Querystring


90

Sono abbastanza nuovo su Go e non ho ancora capito tutto. In molti dei linguaggi moderni Node.js, Angular, jQuery, PHP è possibile eseguire una richiesta GET con parametri di stringa di query aggiuntivi.

Fare questo in Go non è così semplice come sembra, e non riesco ancora a capirlo. Non voglio davvero dover concatenare una stringa per ciascuna delle richieste che voglio fare.

Ecco lo script di esempio:

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 questo esempio puoi vedere che c'è un URL, che richiede una variabile GET di api_key con la tua chiave api come valore. Il problema è che questo diventa hard coded sotto forma di:

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

C'è un modo per costruire dinamicamente questa stringa di query? Al momento dovrò assemblare l'URL prima di questo passaggio per ottenere una risposta valida.


1
Allora cosa c'è di sbagliato nel concatenare una stringa?
Salvador Dali

4
Suppongo niente, ma non è davvero una soluzione elegante, ho solo pensato che ci fosse un modo migliore di fare le cose in Go. Vedi le modifiche all'azione, al metodo e poi devi mettere insieme tutto.
Rudi Strydom

2
Puoi usare url.Valuesil Encodemetodo di. Puoi anche utilizzare URL.Stringper creare l'intero URL.
Dave C

Risposte:


213

Come ha detto un commentatore, puoi ottenere Valuesda net/urlquale ha un Encodemetodo. Potresti fare qualcosa del genere ( req.URL.Query()restituisce l'esistente 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
Fantastico grazie amico! È esattamente quello che stavo cercando!
Rudi Strydom

Ottimo anche per i test!
Kyle Chadha

Qualche soluzione per rendere i parametri della stringa di query nell'ordine desiderato? Le chiavi sono ordinate in Encode()metodo.
artificerpi

1
@artificerpi se fosse fondamentale per qualche motivo potresti reimplementare ciò che fanno all'interno del metodo Encode golang.org/src/net/url/url.go?s=24222:24253#L845 Ma mi chiedo perché sia ​​importante.
jcbwlkr

3
Non è necessario utilizzare NewRequest se non si sta facendo nulla con esso. Puoi semplicemente usare url.Parse("https://something.com/")invece o persino creare direttamente un oggetto URL.
Richard

36

Usalo r.URL.Query()quando aggiungi una query esistente, se stai costruendo un nuovo set di parametri usa la url.Valuesstruttura in questo modo

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
}

14

Usare NewRequestsolo per creare un URL è eccessivo. Usa il net/urlpacchetto:

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

Parco giochi: https://play.golang.org/p/YCTvdluws-r


D'accordo, ottima risposta!
pow-il

Questa dovrebbe essere davvero la risposta accettata.
Paul
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.