HTTP.Get से JSON की प्रतिक्रिया कैसे प्राप्त करें


135

मैं वेब से 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()
}

जवाबों:


266

आदर्श तरीका उपयोग करना नहीं है 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/ आदि कॉल)। कारण यह है कि डिफ़ॉल्ट क्लाइंट का कोई टाइमआउट सेट नहीं है; यदि दूरस्थ सर्वर अप्रतिसादी है, तो आपका दिन खराब होने वाला है।


5
ऐसा लगता है जैसे आपको संरचना में वस्तुओं के नाम के लिए अपरकेस का उपयोग करने की आवश्यकता है, उदाहरण के लिए type WebKeys struct { Keys []struct { X5t string X5c []string } } , जब जेएसएन में आप जो पार्स कर रहे हैं, उसमें वास्तविक पैरामीटर कम मामले में हैं। JSON उदाहरण:{ "keys": [{ "x5t": "foo", "x5c": "baaaar" }] }
विल्सन

1
@ रोमान, नहीं। यदि कोई त्रुटि दी गई है, तो प्रतिक्रिया मान शून्य है। (एक त्रुटि का अर्थ है कि हम किसी भी मान्य HTTP प्रतिक्रिया को नहीं पढ़ सकते हैं, बंद करने के लिए कोई निकाय नहीं है!) आप एक गैर-मौजूद URL पर इंगित (.Get) द्वारा इसका परीक्षण कर सकते हैं। Tis पद्धति को दूसरे कोड ब्लॉक में नेट / http डॉक्स में प्रदर्शित किया जाता है।
कॉनर पीट

1
@NamGVU एक संभावित आवंटन बचाता है और http का उपयोग करने के लिए कनेक्शन को फिर से जीवित रखने की अनुमति देता है।
कॉनर पीट

2
@ConnorPeet आपने मेरा दिन शुक्रिया अदा किया! मुझे आश्चर्य है कि "आप उत्पादन में डिफ़ॉल्ट * http.Client संरचना का उपयोग नहीं करना चाहिए" के साथ क्या मतलब था। क्या आपका मतलब यह था कि एक &http.Client{Timeout: 10 * time.Second}पूरी लाइब्रेरी / रणनीति का उपयोग या उपयोग करना चाहिए ?
जोना रोड्रिग्स

6
बस दूसरों के लिए एक चेतावनी - कुछ प्रकार के विकृत JSON के लिए एक त्रुटि वापस नहींjson.NewDecoder(r.Body).Decode(target) होगी ! मैं बस कुछ घंटे बर्बाद करने की कोशिश कर रहा हूं यह समझने की कोशिश कर रहा हूं कि मुझे खाली प्रतिक्रिया क्यों मिलती रही - स्रोत से पता चलता है कि JSON में एक अतिरिक्त अल्पविराम था जहां यह नहीं होना चाहिए था। मेरा सुझाव है कि आप इसके बजाय उपयोग करें । यहाँ भी अन्य संभावित खतरों के बारे में एक अच्छा json.Unmarshaljson.Decoder
राइटअप

25

आपकी समस्या आपके डेटा में स्लाइस की घोषणाएं थीं structs(इसके अलावा Track, उन्हें स्लाइस नहीं होना चाहिए ...)। यह कुछ अधिक नासमझ फील्डनामों द्वारा कंपाउंड किए गए भ्रूण फ़ाइल में था, जिसे स्ट्रक्चरटैग के माध्यम से तय किया जा सकता है, गोडॉक देखें ।

नीचे दिए गए कोड ने जसन को सफलतापूर्वक पार कर दिया। यदि आपके और प्रश्न हैं, तो मुझे बताएं।

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

1
प्रतिक्रिया शरीर में कुछ है।
पीटरो

6
मेरे मामले में, मुझे "स्ट्रक्चर" फ़ील्ड में UPPER-CASE पहला चरित्र याद आ रहा था।
त्याग दें

नीचे दिए गए उत्तर सही है, एक डिकोडर का उपयोग सीधे प्रतिक्रिया पर करता है। जो अनावश्यक आवंटन से बचता है और आम तौर पर अधिक विचारधारात्मक है। मेरे उत्तर को ठीक किया, इसे इंगित करने के लिए धन्यवाद।
टिक

@abourget omg इस टिप्पणी के लिए धन्यवाद। पार्सर में समस्याओं की तलाश में सिर्फ 1 घंटे का समय
बिताएं

14

आपको अपनी संकुल में ऊपरी केस प्रॉपर्टी के नाम की जरूरत है ताकि जसन पैकेज का उपयोग किया जा सके।

अपर केस प्रॉपर्टी के नाम हैं 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()
}

अभी भी काम नहीं कर रहा है, क्या यह आपके लिए काम कर रहा है? वही खाली प्रतिक्रिया
अक्षयदीप गिरी

3
"आपको अपने संकुल में ऊपरी केस प्रॉपर्टी के नाम की जरूरत है ताकि जौन संकुल द्वारा उपयोग किया जा सके।"
HVNSweeting

8

json.Unmarshal(से var data interface{}) के परिणाम सीधे आपके गो प्रकार और चर घोषणाओं से मेल नहीं खाते हैं। उदाहरण के लिए,

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]]]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.