解组JSON HTTP响应

Itay Karo:

我最近开始玩GO,并且尝试从http://www.oref.org.il/WarningMessages/alerts.json解组JSON响应
由于某种原因,我无法理解解编失败,解组的结构为空(我的猜测是某种程度上与编码有关)。

以下是代码,感谢您的帮助。

谢谢老爸

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"
  "encoding/json"
)

const alertsUrl = "http://www.oref.org.il/WarningMessages/alerts.json"

type Record struct {
  Id string `json:id`
  Title string `json:title`
  Data []string `json:data`
}

func main() {
  client := &http.Client{}
  req, err := http.NewRequest("GET", alertsUrl, nil)
  perror(err)

  req.Header.Add("Content-Type", "application/json; charset=utf-8")
  res, err := client.Do(req)
  perror(err)

  defer res.Body.Close()
  body, err := ioutil.ReadAll(res.Body)
  perror(err)

  var record Record
  json.Unmarshal(body, &record)
  fmt.Println(record)
}

func perror(err error) {
  if err != nil {
    panic(err)
  }
}
补语:

您正在忽略JSON Unmarshal上的错误

func Unmarshal(data []byte, v interface{}) error

看到它返回一个错误。加进去

err = json.Unmarshal(body, &record)
perror(err)

看来这是Unicode错误-您需要解码UTF-16数据

你应该怎么做?看看这个答案基本上,一旦您像读取了正文body, err := ioutil.ReadAll(res.Body),便想将UTF-16字节解码为字符串。有很多事情要做,但我们可以采取一些自由行动:例如,在Chrome中拉起URL,浏览器告诉我们它是UTF-16 LE。因此,我们可以跳过ByteOrder检测。所以这里的关键是这个功能:

func UTF16BytesToString(b []byte, o binary.ByteOrder) string {
    utf := make([]uint16, (len(b)+(2-1))/2)
    for i := 0; i+(2-1) < len(b); i += 2 {
        utf[i/2] = o.Uint16(b[i:])
    }
    if len(b)/2 < len(utf) {
        utf[len(utf)-1] = utf8.RuneError
    }
    return string(utf16.Decode(utf))
}

知道我们的字节顺序并将其传递后,这会将原始字节数组转换为UTF-16字符的字符串。感谢用户OneOfOne的评论,我们还可以轻松检测BOM。

结果:

package main

import (
    "encoding/binary"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "unicode/utf16"
    "unicode/utf8"
)

const alertsUrl = "http://www.oref.org.il/WarningMessages/alerts.json"

type Record struct {
    Id    string   `json:id`
    Title string   `json:title`
    Data  []string `json:data`
}

// LazyUTF16BytesToString converts UTF-16 encoded bytes, in big or little endian byte order,
// to a UTF-8 encoded string.
func LazyUTF16BytesToString(b []byte) string {
    if len(b)%2 != 0 {
        panic("len(b) % 2 != 0")
    }

    var codec binary.ByteOrder = binary.LittleEndian
    if b[0] == 0xFE && b[1] == 0xFF { //check and strip the BOM
        b = b[2:]
        codec = binary.BigEndian
    } else if b[0] == 0xFF && b[1] == 0xFE {
        b = b[2:]
    }

    utf := make([]uint16, (len(b)+(2-1))/2)
    for i := 0; i+(2-1) < len(b); i += 2 {
        utf[i/2] = codec.Uint16(b[i:])
    }
    if len(b)/2 < len(utf) {
        utf[len(utf)-1] = utf8.RuneError
    }
    return string(utf16.Decode(utf))
}

func main() {
    client := &http.Client{}
    req, err := http.NewRequest("GET", alertsUrl, nil)
    perror(err)

    req.Header.Add("Content-Type", "application/json; charset=utf-8")
    res, err := client.Do(req)
    perror(err)

    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    perror(err)

    bodyString := LazyUTF16BytesToString(body)

    var record Record
    err = json.Unmarshal([]byte(bodyString), &record)
    perror(err)
    fmt.Println(record)
}

func perror(err error) {
    if err != nil {
        panic(err)
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章