Как получить ответ JSON в Golang
Я пытаюсь прочитать данные JSON из интернета, но этот код возвращает пустой результат. Я не уверен, что я делаю неправильно здесь.
package main
import "os"
import "fmt"
import "net/http"
import "io/ioutil"
import "encoding/json"
type Tracks struct {
Toptracks []Toptracks_info
}
type Toptracks_info struct {
Track []Track_info
Attr []Attr_info
}
type Track_info struct {
Name string
Duration string
Listeners string
Mbid string
Url string
Streamable []Streamable_info
Artist []Artist_info
Attr []Track_attr_info
}
type Attr_info struct {
Country string
Page string
PerPage string
TotalPages string
Total string
}
type Streamable_info struct {
Text string
Fulltrack string
}
type Artist_info struct {
Name string
Mbid string
Url string
}
type Track_attr_info struct {
Rank string
}
func get_content() {
// json data
url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands"
res, err := http.Get(url)
if err != nil {
panic(err.Error())
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err.Error())
}
var data Tracks
json.Unmarshal(body, &data)
fmt.Printf("Results: %vn", data)
os.Exit(0)
}
func main() {
get_content()
}
4 ответа:
идеально не использовать ioutil.ReadAll, а скорее использовать декодер на читателе напрямую. Вот хорошая функция, которая получает url и декодирует свой ответ на
target
структура.var myClient = &http.Client{Timeout: 10 * time.Second} func getJson(url string, target interface{}) error { r, err := myClient.Get(url) if err != nil { return err } defer r.Body.Close() return json.NewDecoder(r.Body).Decode(target) }
пример использования:
type Foo struct { Bar string } func main() { foo1 := new(Foo) // or &Foo{} getJson("http://example.com", foo1) println(foo1.Bar) // alternately: foo2 := Foo{} getJson("http://example.com", &foo2) println(foo2.Bar) }
вы не должны использовать значение по умолчанию *http.Структура клиента в производстве, как этот ответ первоначально продемонстрировал! (Что и есть http.Получить/и т. д. вызов). Причина в том, что клиент по умолчанию не имеет тайм-аута; если удаленный сервер не отвечает, У вас будет плохой день.
ваша проблема заключалась в объявлениях среза в ваших данных
structs
(кромеTrack
, они не должны быть кусочками...). Это было усугублено некоторыми довольно глупыми именами полей в извлеченном файле json, которые могут быть исправлены с помощью structtags, см. godoc.приведенный ниже код успешно проанализировал json. Если у вас есть еще вопросы, дайте мне знать.
package main import "fmt" import "net/http" import "io/ioutil" import "encoding/json" type Tracks struct { Toptracks Toptracks_info } type Toptracks_info struct { Track []Track_info Attr Attr_info `json: "@attr"` } type Track_info struct { Name string Duration string Listeners string Mbid string Url string Streamable Streamable_info Artist Artist_info Attr Track_attr_info `json: "@attr"` } type Attr_info struct { Country string Page string PerPage string TotalPages string Total string } type Streamable_info struct { Text string `json: "#text"` Fulltrack string } type Artist_info struct { Name string Mbid string Url string } type Track_attr_info struct { Rank string } func perror(err error) { if err != nil { panic(err) } } func get_content() { url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" res, err := http.Get(url) perror(err) defer res.Body.Close() decoder := json.NewDecoder(res.Body) var data Tracks err = decoder.Decode(&data) if err != nil { fmt.Printf("%T\n%s\n%#v\n",err, err, err) switch v := err.(type){ case *json.SyntaxError: fmt.Println(string(body[v.Offset-40:v.Offset])) } } for i, track := range data.Toptracks.Track{ fmt.Printf("%d: %s %s\n", i, track.Artist.Name, track.Name) } } func main() { get_content() }
вам нужны имена свойств верхнего регистра в ваших структурах для использования пакетами json.
имена свойств верхнего регистра
exported properties
. Имена свойств в нижнем регистре не экспортируются.вам также необходимо передать объект данных по ссылке (
&data
).package main import "os" import "fmt" import "net/http" import "io/ioutil" import "encoding/json" type tracks struct { Toptracks []toptracks_info } type toptracks_info struct { Track []track_info Attr []attr_info } type track_info struct { Name string Duration string Listeners string Mbid string Url string Streamable []streamable_info Artist []artist_info Attr []track_attr_info } type attr_info struct { Country string Page string PerPage string TotalPages string Total string } type streamable_info struct { Text string Fulltrack string } type artist_info struct { Name string Mbid string Url string } type track_attr_info struct { Rank string } func get_content() { // json data url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" res, err := http.Get(url) if err != nil { panic(err.Error()) } body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err.Error()) } var data tracks json.Unmarshal(body, &data) fmt.Printf("Results: %v\n", data) os.Exit(0) } func main() { get_content() }
результаты
json.Unmarshal
(вvar data interface{}
) не совпадают напрямую с объявлениями типа Go и переменных. Например,package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" ) type Tracks struct { Toptracks []Toptracks_info } type Toptracks_info struct { Track []Track_info Attr []Attr_info } type Track_info struct { Name string Duration string Listeners string Mbid string Url string Streamable []Streamable_info Artist []Artist_info Attr []Track_attr_info } type Attr_info struct { Country string Page string PerPage string TotalPages string Total string } type Streamable_info struct { Text string Fulltrack string } type Artist_info struct { Name string Mbid string Url string } type Track_attr_info struct { Rank string } func get_content() { // json data url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" url += "&limit=1" // limit data for testing res, err := http.Get(url) if err != nil { panic(err.Error()) } body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err.Error()) } var data interface{} // TopTracks err = json.Unmarshal(body, &data) if err != nil { panic(err.Error()) } fmt.Printf("Results: %v\n", data) os.Exit(0) } func main() { get_content() }
выход:
Results: map[toptracks:map[track:map[name:Get Lucky (feat. Pharrell Williams) listeners:1863 url:http://www.last.fm/music/Daft+Punk/_/Get+Lucky+(feat.+Pharrell+Williams) artist:map[name:Daft Punk mbid:056e4f3e-d505-4dad-8ec1-d04f521cbb56 url:http://www.last.fm/music/Daft+Punk] image:[map[#text:http://userserve-ak.last.fm/serve/34s/88137413.png size:small] map[#text:http://userserve-ak.last.fm/serve/64s/88137413.png size:medium] map[#text:http://userserve-ak.last.fm/serve/126/88137413.png size:large] map[#text:http://userserve-ak.last.fm/serve/300x300/88137413.png size:extralarge]] @attr:map[rank:1] duration:369 mbid: streamable:map[#text:1 fulltrack:0]] @attr:map[country:Netherlands page:1 perPage:1 totalPages:500 total:500]]]