[英]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
獲取結構的Headers
和Status
字段。
我知道有一些事情需要處理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-dependent
於type-dependent
默認編碼:
實施這是你可以做的
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.