猿问

无法从 HTTP 响应中解析 JSON

因此,我试图弄清楚如何获取以下代码以正确解析来自https://api.coinmarketcap.com/v1/ticker/ethereum的 JSON 数据。解码来自http://echo.jsontest.com/key1/value1/key2/value2的响应中的 JSON 数据似乎没有问题,但在指向 CoinMarketCap API 时只会获得空值/零值。


package main


import(

  "encoding/json"

  "net/http"

  "log"

)


type JsonTest struct {

  Key1  string

  Key2  string

}


type CoinMarketCapData struct {

  Id               string

  Name             string

  Symbol           string

  Rank             int

  PriceUSD         float64

  PriceBTC         float64

  Volume24hUSD     float64

  MarketCapUSD     float64

  AvailableSupply   float64

  TotalSupply       float64

  PercentChange1h   float32

  PercentChange24h float32

  PercentChange7d   float32

}


func getJson(url string, target interface{}) error {

  client := &http.Client{}

  req, _ := http.NewRequest("GET", url, nil)

  req.Header.Set("Content-Type", "application/json")

  r, err := client.Do(req)

  if err != nil {

      return err

  }

  defer r.Body.Close()

  return json.NewDecoder(r.Body).Decode(target)

}


func main() {

  //Test with dummy JSON

  url1 := "http://echo.jsontest.com/key1/value1/key2/value2"

  jsonTest := new(JsonTest)

  getJson(url1, jsonTest)

  log.Printf("jsonTest Key1: %s", jsonTest.Key1)


  //Test with CoinMarketCap JSON

  url2 := "https://api.coinmarketcap.com/v1/ticker/ethereum"

  priceData := new(CoinMarketCapData)

  getJson(url2, priceData)

  //Should print "Ethereum Id: ethereum"

  log.Printf("Ethereum Id: %s", priceData.Id)

}

我怀疑这与 CoinMarketCap 的 JSON 位于顶级 JSON 数组中的事实有关,但我尝试了各种迭代,例如:


priceData := make([]CoinMarketCapData, 1)

无济于事。非常感谢任何建议,谢谢。


慕尼黑8549860
浏览 242回答 2
2回答

30秒到达战场

JSON 是一个数组,因此您需要将一个数组传递给 Decode 方法。还记得检查返回的错误。package mainimport(  "encoding/json"  "net/http"  "log")type CoinMarketCapData struct {  Id               string  Name             string  Symbol           string  Rank             int  PriceUSD         float64  PriceBTC         float64  Volume24hUSD     float64  MarketCapUSD     float64  AvailableSupply   float64  TotalSupply       float64  PercentChange1h   float32  PercentChange24h float32  PercentChange7d   float32}func getJson(url string, target interface{}) error {  client := &http.Client{}  req, _ := http.NewRequest("GET", url, nil)  req.Header.Set("Content-Type", "application/json")  r, err := client.Do(req)  if err != nil {      return err  }  defer r.Body.Close()  return json.NewDecoder(r.Body).Decode(target)}func main() {  //Test with CoinMarketCap JSON  url2 := "https://api.coinmarketcap.com/v1/ticker/ethereum"  priceData := make([]CoinMarketCapData, 0)  err := getJson(url2, &priceData)  if err != nil {     log.Printf("Failed to decode json: %v", err)  } else {    //Should print "Ethereum Id: ethereum"    log.Printf("Ethereum Id: %v", priceData[0].Id)  }}运行此打印2016/08/21 17:15:27 Ethereum Id: ethereum

哈士奇WWW

你是对的,顶级 API 响应类型是一个列表,它必须反映在解组过程中。解决此问题的一种方法是将您的MarketCap响应定义为切片,如下所示:package mainimport (    "encoding/json"    "log"    "net/http")// curl -sLf "https://api.coinmarketcap.com/v1/ticker/ethereum" | JSONGen// command line helper: `go get github.com/bemasher/JSONGen`type MarketCapResponse []struct {    AvailableSupply  float64 `json:"available_supply"`    HVolumeUsd       float64 `json:"24h_volume_usd"`    Id               string  `json:"id"`    MarketCapUsd     float64 `json:"market_cap_usd"`    Name             string  `json:"name"`    PercentChange1h  float64 `json:"percent_change_1h"`    PercentChange24h float64 `json:"percent_change_24h"`    PercentChange7d  float64 `json:"percent_change_7d"`    PriceBtc         float64 `json:"price_btc"`    PriceUsd         float64 `json:"price_usd"`    Rank             int64   `json:"rank"`    Symbol           string  `json:"symbol"`    TotalSupply      float64 `json:"total_supply"`}然后解组就可以正常工作了。需要注意的一点是指向切片的指针与切片不同。特别是指针不支持索引,这就是为什么需要先取消引用才能访问列表中的第一项。func getAndUnmarshal(url string, target interface{}) error {    var client = &http.Client{}    req, _ := http.NewRequest("GET", url, nil)    req.Header.Set("Content-Type", "application/json")    r, _ := client.Do(req)    defer r.Body.Close()    return json.NewDecoder(r.Body).Decode(target)}func main() {    link := "https://api.coinmarketcap.com/v1/ticker/ethereum"    resp := new(MarketCapResponse)    getAndUnmarshal(link, resp)    log.Printf("Ethereum Id: %s", (*resp)[0].Id)    // prints:    // 2016/08/22 02:13:23 Ethereum Id: ethereum}另一种方法是为单个MarketCap定义一个类型,然后在需要时创建一个切片作为目标:package main// curl -sLf "https://api.coinmarketcap.com/v1/ticker/ethereum" | jq .[0] | JSONGentype MarketCap struct {    AvailableSupply  float64 `json:"available_supply"`    HVolumeUsd       float64 `json:"24h_volume_usd"`    Id               string  `json:"id"`    MarketCapUsd     float64 `json:"market_cap_usd"`    Name             string  `json:"name"`    PercentChange1h  float64 `json:"percent_change_1h"`    PercentChange24h float64 `json:"percent_change_24h"`    PercentChange7d  float64 `json:"percent_change_7d"`    PriceBtc         float64 `json:"price_btc"`    PriceUsd         float64 `json:"price_usd"`    Rank             int64   `json:"rank"`    Symbol           string  `json:"symbol"`    TotalSupply      float64 `json:"total_supply"`}func getAndUnmarshal(url string, target interface{}) error {     ...}func main() {    link := "https://api.coinmarketcap.com/v1/ticker/ethereum"    resp := make([]MarketCap, 0)    getAndUnmarshal(link, &resp)    log.Printf("Ethereum Id: %s", resp[0].Id)    // 2016/08/22 02:13:23 Ethereum Id: ethereum}什么更适合您将取决于您的用例。如果您希望结构反映 API 响应,那么第一种方法似乎更合适。MarketCap是一件事吗?我相信,API 只是访问它的一种方式,比第二种方式更合适。
随时随地看视频慕课网APP

相关分类

Go
我要回答