簡體   English   中英

Golang 結構具有 io.Reader 無法序列化

[英]Golang struct having io.Reader unable to serialize

我試圖將下面的 struct 序列化為byte[]以將其存儲到 DB 中,然后在從 DB 讀取它時我正在反序列化它。

type Response struct {
    Headers map[string][]string
    Body    io.Reader
    Status  int
}

下面是我如何創建響應對象並為其設置值的代碼。

resp := new(Response)
resp.Body = bytes.NewReader(outBytes) //outBytes is byte[]
resp.Headers.SetKeyValue("Content-Type", "text/json") //SetKeyValue is the method created for adding headers
resp.Headers.SetKeyValue("Url-Type", "broker")
resp.Status = 200

我正在使用json.Marshal()序列化resp對象,如下所示。

b, _ := json.Marshal(resp)

下面是我用來反序列化的代碼。

var r Response
r.Body = &bytes.Buffer{}
json.Unmarshal(b,&r)

問題在於反序列化,我無法獲得resp.Body對象。 盡管設置了 body 對象(見上文),它始終為nil或空白。 我能夠從反序列化而不是Body獲取結構的HeadersStatus字段。

我知道有一些事情需要處理Body字段,它是一個io.Reader

任何幫助都會很棒。

簡短回答: JSON 編組器不會使用Read()函數從 io.Reader 讀取字符串。 您可以使用實現Marshaler接口的類型,而不是使用io.Reader

Marshaller 的工作原理: Marshal 遞歸地遍歷值 v。 如果遇到的值實現了Marshaler接口並且不是 nil 指針,Marshal 將調用其MarshalJSON方法來生成 JSON。 如果不存在 MarshalJSON 方法但該值實現encoding.TextMarshaler ,則 Marshal 調用其MarshalText方法。 nil 指針異常並不是絕對必要的,但在 UnmarshalJSON 的行為中模仿了類似的必要異常。

否則,Marshal 使用以下type-dependenttype-dependent默認編碼:

  • 布爾值編碼為 JSON 布爾值。
  • 浮點、整數和數字值編碼為 JSON 數字。

實施這是你可以做的

type Response struct {
    Headers map[string][]string
    Body    *JSONReader
    Status  int
}

type JSONReader struct {
    *bytes.Reader
}

func NewJSONReader(outBytes []byte) *JSONReader {
    jr := new(JSONReader)
    jr.Reader = bytes.NewReader(outBytes)
    return jr
}

func (js JSONReader) MarshalJSON() ([]byte, error) {
    data, err := ioutil.ReadAll(js.Reader)
    if err != nil {
        return nil, err
    }
    data = []byte(`"` + string(data) + `"`)
    return data, nil
}

// UnmarshalJSON sets *jr to a copy of data.
func (jr *JSONReader) UnmarshalJSON(data []byte) error {
    if jr == nil {
        return errors.New("json.JSONReader: UnmarshalJSON on nil pointer")
    }
    if data == nil {
        return nil
    }
    data = []byte(strings.Trim(string(data), "\""))
    jr.Reader = bytes.NewReader(data)
    return nil
}

這是一個帶有實現和示例使用的 go playground 鏈接:鏈接

概述

io.Reader是一個接口,所以它不能被編組。 每個封送處理結構屬性必須實現要封送處理的Marshaler接口。 您可以聲明自己的封送bytes.Reader器包裝結構來封送來自bytes.Reader數據。

為什么接口不能被編組?

Go 中的接口提供了一種指定對象行為的方法:如果某些東西可以做到這一點,那么它就可以在這里使用。 相反,Go 的結構體是類型化的字段集合。 它們可用於將數據分組以形成記錄。 Go 支持在結構類型而不是接口類型上定義的方法。

執行

type Response struct {
    Body *MarshalableReader
}

type MarshalableReader struct {
    *bytes.Reader
}

func (r MarshalableReader) MarshalJSON() ([]byte, error) {
    data, err := ioutil.ReadAll(r.Reader)
    if err != nil {
        return nil, err
    }
    return []byte(fmt.Sprintf("\"%s\"", data)), nil
}

func main() {
    resp := Response{&MarshalableReader{bytes.NewReader([]byte("Blah Blah"))}}

    marshaled, err := json.Marshal(resp)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("JSON: %s\n", marshaled)
}                                                                                               

我正在使用"encoding/json"包: https : //golang.org/pkg/encoding/json/

因為我可以使用 http.ResponseWriter 發送 JSON 響應。 這里有兩個函數可以用來發送 JSON 和從 body 中讀取 JSON:

// GetJSONContent returns the JSON content of a request
func GetJSONContent(v interface{}, r *http.Request) error {
    defer r.Body.Close()
    return json.NewDecoder(r.Body).Decode(v)
}

// JSONWithHTTPCode Json Output with an HTTP code
func JSONWithHTTPCode(w http.ResponseWriter, d interface{}, code int) {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.WriteHeader(code)
    if d != nil {
        err := json.NewEncoder(w).Encode(d)
        if err != nil {
            panic(err)
        }
    }
}

然后在您的處理程序中使用這些 func 如下:

// Handler handler
func Handler(w http.ResponseWriter, r *http.Request) {
        s := YourStruct{}
        err = GetJSONContent(s, r) 
        if err != nil {
            panic(err)
        }
        return
    }

    JSONWithHTTPCode(w, s, http.StatusOK)
}

希望有幫助

暫無
暫無

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

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