如何在Golang中获得JSON响应
我试图从Web读取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: %v\n", data) os.Exit(0) } func main() { get_content() }
理想的方法不是使用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.Client结构,因为这个答案最初的演示! (这是什么http.get / etc调用)。 原因是默认的客户端没有超时设置; 如果远程服务器没有响应,你将会有一个糟糕的一天。
你的问题是你的数据structs
中的切片声明(除了Track
,它们不应该是切片…)。 这是由一些相当愚蠢的字段名在json文件中提取的,可以通过structtags修改,参见godoc 。
下面的代码成功parsing了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{}
)的结果并不直接匹配你的Gotypes和variables声明。 例如,
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]]]