简体   繁体   English

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

[英]Go unmarshalling JSON from compessed HTTP: invalid character looking for beginning of value

I've just written my first Go application which downloads and unmarshales simple JSON object over http. 我刚刚编写了第一个Go应用程序,该应用程序通过http下载并解组了简单的JSON对象。 Http content is compressed: 'content-encoding': 'deflate' Http内容被压缩: 'content-encoding': 'deflate'

I used several well-known examples (like this ). 我用几个众所周知的例子(如 )。 Unfortunately the application fails to parse the desired JSON with quite rare and strange error. 不幸的是,该应用程序无法解析所需的JSON,并且出现了非常罕见的奇怪错误。 I wasn't able to find out what's the problem. 我无法找出问题所在。 Any help will be appreciated. 任何帮助将不胜感激。

JSON input (Python was used for debugging) JSON输入 (使用Python进行调试)

In [8]: r = requests.get("http://172.17.0.31:20000/top")

In [9]: r.text
Out[9]: u'{"timestamp":{"tv_sec":1428447555,"tv_usec":600186},"string_timestamp":"2015-04-07 22:59:15.600186","monitor_status":"enabled"}'
In [18]: r.headers
Out[18]: {'content-length': '111', 'content-type': 'application/json', 'connection': 'close', 'content-encoding': 'deflate'}

Source code ( UPDATED according to the answers) 源代码 (根据答案更新

package main

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

Error 错误

[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>}
[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]
panic: invalid character 'x' looking for beginning of value

UPD: Thanks everyone. UPD:谢谢大家。 Now it's obvious that the reason of this issue was a deflate compression of HTTP response. 现在很明显,这个问题的原因是deflate HTTP响应的压缩。 However, it's still not clear how to perform a decompression in Golang (see here ). 但是,仍然不清楚如何在Golang中执行减压(请参阅此处 )。

The Go JSON marshaller can only marshal unicode strings. Go JSON封送处理程序只能封送unicode字符串。 It seems that your JSON is not encoded in unicode, but with some other encoding (deflate?). 看来您的JSON不是以Unicode编码,而是以其他某种编码(放气?)进行编码。

If you take your bytes stream: 如果您使用字节流:

[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]

And try to get a unicode string out of it: 并尝试从中获取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))

You would see a weird (compressed?) string in the console, not JSON. 您会在控制台中看到一个奇怪的(压缩的?)字符串,而不是JSON。

I guess that the python http client automatically decompresses the deflated bytes while the Go http client does not (I know it does so for gzip but not sure if for deflate). 我猜想python http客户端会自动解压缩已压缩的字节,而Go http客户端不会(我知道gzip会这样做,但不确定是否要压缩)。 You would have to read out the deflated bytes and convert them into a unicode string before you will be able to use the JSON marshaller to parse them. 您必须先读出压缩后的字节并将其转换为unicode字符串,然后才能使用JSON编组器对其进行解析。

I don't know about 'x', but struct fields must be public (start with a capital letter) to be considered by the json Unmarshaller. 我不知道'x',但是json Unmarshaller会考虑struct字段必须是公共的(以大写字母开头)。 Of course then the names don't match the json keys, and you have to add json annotations like so: 当然,然后这些名称与json键不匹配,并且您必须添加json注释,如下所示:

type Top struct {
    Timestamp        Timestamp `json:"timestamp"`
    String_timestamp string `json:"string_timestamp"`
    Monitor_status   string `json:"monitor_status"`
}

I believe this is due to you double encoding. 我相信这是由于您进行了双重编码。 ioutil.ReadAll(res.Body) returns a []byte so when you do []byte(body) you're casting what is already a byte array, my guess is that first bytes UTF value is x . ioutil.ReadAll(res.Body)返回一个[]byte因此当您执行[]byte(body)您正在转换已经是字节数组的东西,我猜想第一个字节的UTF值为x Just update this; 只需更新一下; json.Unmarshal([]byte(body), &jsondata) to json.Unmarshal(body, &jsondata) and I bet it will unmarshal just fine. json.Unmarshal([]byte(body), &jsondata)json.Unmarshal(body, &jsondata) ,我敢打赌,它将解组就好了。

Also, unrelated to your error but as pointed out in the other answer if you do not export the fields in your struct (in go this means start the field name with a capital letter) then the unmarshaler will not be able to make user of them. 另外,与您的错误无关,但如其他答案所指出,如果您不导出结构中的字段(这样做意味着用大写字母开头字段名称),则拆封程序将无法使它们成为用户。 To make that work you need to update you type to; 为了完成这项工作,您需要将输入内容更新为;

type Top struct {
    Timestamp        Timestamp `json:"timestamp"`
    String_timestamp string `json:"string_timestamp"`
    Monitor_status   string `json:"monitor_status"`
}

The json annotations are required because the unmarshaler is very strict and requires exact matches (case sensitive) for field names. 需要json批注,因为拆组器非常严格,并且要求字段名称完全匹配(区分大小写)。

Try this please 请尝试这个

func get_content() {

    url := "http://172.17.0.31:20000/top"

    res, err := http.Get(url)
    if err != nil {
        panic(err.Error())
    }
    defer res.Body.Close()

    fmt.Println("res body:", res.Body)

    body, err := ioutil.ReadAll(resp=.Body)

    fmt.Println("body:", body)
    re, err := zlib.NewReader(bytes.NewReader(body))
    fmt.Println("zlib:", re)
    enflated, err := ioutil.ReadAll(re)
    fmt.Println("enflated:", string(enflated))

    var jsondata Top
    err = json.Unmarshal(body, &jsondata)
    if err != nil {
        panic(err.Error())
    }

    fmt.Println(jsondata)
}

and ensure http://172.17.0.31:20000/top return json type. 并确保http://172.17.0.31:20000/top返回json类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 解组 JSON 返回错误:无效字符 &#39;\\x1f&#39; 寻找值的开头 - Unmarshalling JSON returns an error: invalid character '\x1f' looking for beginning of value Golang无效字符&#39;b&#39;寻找值的开始 - Golang invalid character 'b' looking for beginning of value golang websocket.JSON.Receive无效字符&#39;q&#39;寻找值的开头 - golang websocket.JSON.Receive invalid character 'q' looking for beginning of value JSON无效字符&#39;}&#39;正在寻找对象键字符串的开头 - JSON invalid character '}' looking for beginning of object key string Parse.com说“寻找值的开头的无效字符&#39;\\” - Parse.com says “invalid character '\'' looking for beginning of value” “无效字符&#39;u&#39;寻找值的开始”使用golang开发的服务解析错误 - “invalid character 'u' looking for beginning of value”Parsing Error from an Service developed in golang json 格式无效,请检查。 原因:寻找对象键字符串开头的无效字符“a” - Invalid json format, please check. Reason: invalid character 'a' looking for beginning of object key string JSON无法写入创世纪块:无效字符&#39;\\\\&#39;寻找对象密钥字符串的开头 - JSON failed to write genesis block: invalid character '\\' looking for beginning of object key string JSON int密钥发布数据e2e(寻找对象密钥字符串开头的无效字符“ 1”) - JSON int key issue data e2e (invalid character '1' looking for beginning of object key string) 在Go中解组复杂的json - Unmarshalling complex json in Go
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM