如何从 http.Get 获取 JSON 响应
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17156371/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get JSON response from http.Get
提问by Akshaydeep Giri
I'm trying read JSON data from web, but that code returns empty result. I'm not sure what I'm doing wrong here.
我正在尝试从网络读取 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()
}
回答by Connor Peet
The ideal way is notto use ioutil.ReadAll, but rather use a decoder on the reader directly. Here's a nice function that gets a url and decodes its response onto a targetstructure.
理想的方法不是使用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)
}
Example use:
使用示例:
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)
}
You should not be using the default *http.Clientstructure in production as this answer originally demonstrated! (Which is what http.Get/etc call to). The reason is that the default client has no timeout set; if the remote server is unresponsive, you're going to have a bad day.
您不应该*http.Client像这个答案最初演示的那样在生产中使用默认结构!(这是http.Get/etc 调用的内容)。原因是默认客户端没有设置超时;如果远程服务器没有响应,那你的日子就不好过了。
回答by tike
Your Problem were the slice declarations in your data structs(except for Track, they shouldn't be slices...). This was compounded by some rather goofy fieldnames in the fetched json file, which can be fixed via structtags, see godoc.
您的问题是数据中的切片声明structs(除了Track,它们不应该是切片......)。这与获取的 json 文件中一些相当愚蠢的字段名复杂化,可以通过 structtags 修复,请参阅 godoc。
The code below parsed the json successfully. If you've further questions, let me know.
下面的代码成功解析了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()
}
回答by Daniel
You need upper case property names in your structs in order to be used by the json packages.
您的结构中需要大写的属性名称才能被 json 包使用。
Upper case property names are exported properties. Lower case property names are not exported.
大写的属性名称是exported properties. 不导出小写属性名称。
You also need to pass the your data object by reference (&data).
您还需要通过引用 ( &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()
}
回答by peterSO
The results from json.Unmarshal(into var data interface{}) do not directly match your Go type and variable declarations. For example,
json.Unmarshal(into 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()
}
Output:
输出:
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]]]

