为了账号安全,请及时绑定邮箱和手机立即绑定

从压缩的 HTTP 中解组 JSON:寻找值开头的无效字符

从压缩的 HTTP 中解组 JSON:寻找值开头的无效字符

Go
侃侃尔雅 2021-09-27 17:40:38
我刚刚编写了我的第一个 Go 应用程序,它通过 http 下载和解组简单的 JSON 对象。Http内容被压缩: 'content-encoding': 'deflate'我使用了几个众所周知的例子(像这样)。不幸的是,应用程序无法解析所需的 JSON,并出现非常罕见和奇怪的错误。我无法找出问题所在。任何帮助将不胜感激。JSON 输入 (使用 Python 进行调试)In [8]: r = requests.get("http://172.17.0.31:20000/top")In [9]: r.textOut[9]: u'{"timestamp":{"tv_sec":1428447555,"tv_usec":600186},"string_timestamp":"2015-04-07 22:59:15.600186","monitor_status":"enabled"}'In [18]: r.headersOut[18]: {'content-length': '111', 'content-type': 'application/json', 'connection': 'close', 'content-encoding': 'deflate'}源代码(根据答案更新)package mainimport (    "encoding/json"    "fmt"    "io/ioutil"    "net/http")type Top struct {    Timestamp        Timestamp `json:"timestamp"`    String_timestamp string    `json:"string_timestamp"`    Monitor_status   string    `json:"monitor_status"`}type Timestamp struct {    Tv_sec  int `json:"tv_sec"`    Tv_usec int `json:"tv_usec"`}func get_content() {    url := "http://172.17.0.31:20000/top"    res, err := http.Get(url)    if err != nil {        panic(err.Error())    }    fmt.Println(res)    body, err := ioutil.ReadAll(res.Body)    if err != nil {        panic(err.Error())    }    fmt.Println(body)    var jsondata Top    err = json.Unmarshal(body, &jsondata)    if err != nil {        panic(err.Error())    }    fmt.Println(jsondata)}func main() {    get_content()}错误[vitaly@thermaltake elliptics-manager]$ go run main.go &{200 OK 200 HTTP/1.1 1 1 map[Content-Type:[application/json] Content-Length:[111] Content-Encoding:[deflate]] 0xc20803e340 111 [] true map[] 0xc208028820 <nil>}panic: invalid character 'x' looking for beginning of valueUPD:谢谢大家。现在很明显,这个问题的原因是deflateHTTP 响应的压缩。但是,目前还不清楚如何在 Golang 中执行解压(请参阅此处)。
查看完整描述

3 回答

?
哔哔one

TA贡献1854条经验 获得超8个赞

Go JSON 编组器只能编组 unicode 字符串。似乎您的 JSON 不是用 unicode 编码的,而是使用其他一些编码(放气?)。


如果您使用字节流:


[120 156 77 203 65 14 130 48 16 70 225 171 152 127 93 76 59 51 162 244 50 13 96 99 154 216 98 232 192 134 112 119 81 55 110 95 190 183 65 83 142 85 251 252 130 223 160 107 168 113 132 119 66 55 145 182 117 108 62 109 249 70 98 234 108 183 27 84 157 83 121 132 191 19 100 221 165 177 210 216 235 137 200 11 123 230 243 207 195 32 79 37 233 52 135 3 235 82 15 29 75 63 60 227 29 251 27 195 90 38 189]

并尝试从中获取 unicode 字符串:


body := []byte{120, 156, 77, 203, 65, 14, 130, 48, 16, 70, 225, 171, 152, 127, 93, 76, 59, 51, 162, 244, 50, 13, 96, 99, 154, 216, 98, 232, 192, 134, 112, 119, 81, 55, 110, 95, 190, 183, 65, 83, 142, 85, 251, 252, 130, 223, 160, 107, 168, 113, 132, 119, 66, 55, 145, 182, 117, 108, 62, 109, 249, 70, 98, 234, 108, 183, 27, 84, 157, 83, 121, 132, 191, 19, 100, 221, 165, 177, 210, 216, 235, 137, 200, 11, 123, 230, 243, 207, 195, 32, 79, 37, 233, 52, 135, 3, 235, 82, 15, 29, 75, 63, 60, 227, 29, 251, 27, 195, 90, 38, 189}

fmt.Println(string(body))

您会在控制台中看到一个奇怪的(压缩的?)字符串,而不是 JSON。


我猜 python http 客户端会自动解压缩压缩的字节,而 Go http 客户端不会(我知道它对 gzip 这样做,但不确定是否对压缩)。您必须读出压缩的字节并将它们转换为 unicode 字符串,然后才能使用 JSON marshaller 解析它们。


查看完整回答
反对 回复 2021-09-27
?
慕姐4208626

TA贡献1852条经验 获得超7个赞

我不知道“x”,但结构字段必须是公共的(以大写字母开头)才能被 json Unmarshaller 考虑。当然,名称与 json 键不匹配,您必须像这样添加 json 注释:


type Top struct {

    Timestamp        Timestamp `json:"timestamp"`

    String_timestamp string `json:"string_timestamp"`

    Monitor_status   string `json:"monitor_status"`

}


查看完整回答
反对 回复 2021-09-27
?
叮当猫咪

TA贡献1776条经验 获得超12个赞

我相信这是由于您进行了双重编码。ioutil.ReadAll(res.Body)返回 a[]byte所以当你[]byte(body)在转换已经是一个字节数组的时候,我的猜测是第一个字节的 UTF 值是x. 只需更新这个; json.Unmarshal([]byte(body), &jsondata)要json.Unmarshal(body, &jsondata)和我打赌它会解组就好了。


此外,与您的错误无关,但正如其他答案中所指出的,如果您不导出结构中的字段(在 go 中,这意味着以大写字母开头的字段名称)那么解组器将无法使用它们. 要完成这项工作,您需要将类型更新为;


type Top struct {

    Timestamp        Timestamp `json:"timestamp"`

    String_timestamp string `json:"string_timestamp"`

    Monitor_status   string `json:"monitor_status"`

}

json 注释是必需的,因为解组器非常严格并且需要字段名称的精确匹配(区分大小写)。


查看完整回答
反对 回复 2021-09-27
  • 3 回答
  • 0 关注
  • 238 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信