我最近开始玩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] 删除。
我来说两句