簡體   English   中英

從精讀的HTTP中解組JSON:無效字符尋找值的開頭

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

我剛剛編寫了第一個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.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'}

源代碼 (根據答案更新

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

錯誤

[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:謝謝大家。 現在很明顯,這個問題的原因是deflate HTTP響應的壓縮。 但是,仍然不清楚如何在Golang中執行減壓(請參閱此處 )。

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編組器對其進行解析。

我不知道'x',但是json Unmarshaller會考慮struct字段必須是公共的(以大寫字母開頭)。 當然,然后這些名稱與json鍵不匹配,並且您必須添加json注釋,如下所示:

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

我相信這是由於您進行了雙重編碼。 ioutil.ReadAll(res.Body)返回一個[]byte因此當您執行[]byte(body)您正在轉換已經是字節數組的東西,我猜想第一個字節的UTF值為x 只需更新一下; json.Unmarshal([]byte(body), &jsondata)json.Unmarshal(body, &jsondata) ,我敢打賭,它將解組就好了。

另外,與您的錯誤無關,但如其他答案所指出,如果您不導出結構中的字段(這樣做意味着用大寫字母開頭字段名稱),則拆封程序將無法使它們成為用戶。 為了完成這項工作,您需要將輸入內容更新為;

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

需要json批注,因為拆組器非常嚴格,並且要求字段名稱完全匹配(區分大小寫)。

請嘗試這個

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)
}

並確保http://172.17.0.31:20000/top返回json類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM