我正在尝试将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对象。尽管设置了体对象,但它总是为零或空白(见上文)。我能够从反序列化中获取结构的Headers和status字段,而不是Body。
我知道有一些东西需要处理Body字段,它是一个io.Reader。
任何帮助都会非常棒。
答案 0 :(得分:5)
简答: JSON marshaller不会使用Read()
函数从io.Reader读取字符串。您可以使用实现io.Reader
接口的类型,而不是使用Marshaler
。
Marshaller的工作原理:
Marshal递归地遍历值v。如果遇到的值实现了Marshaler
接口并且不是nil指针,则Marshal会调用其MarshalJSON
方法来生成JSON。如果没有MarshalJSON方法,但值实现了encoding.TextMarshaler
,Marshal会调用其MarshalText
方法。 nil指针异常不是绝对必要的,但在UnmarshalJSON的行为中模仿了类似的必要异常。
否则,Marshal使用以下type-dependent
默认编码:
<强> Implementaton 强> 这就是你可以做的事情
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操场链接,其中包含实现和示例用法:link
答案 1 :(得分:0)
我正在使用"encoding/json"
包:https://golang.org/pkg/encoding/json/
因为我可以使用http.ResponseWriter发送JSON响应。这里有两个函数可用于发送JSON并从正文中读取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)
}
}
}
然后在你的处理程序中使用这些函数如下:
// 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)
}
希望有所帮助
答案 2 :(得分:0)
io.Reader
是一个接口,因此无法封送。每个编组结构属性必须实现要编组的Marshaler
接口。您可以声明自己的封送程序包装器结构来封送来自bytes.Reader
的数据。
Go中的接口提供了一种指定对象行为的方法:如果有什么可以做到这一点,那么可以在这里使用它。在对面的Go中,结构是字段的类型集合。它们可用于将数据分组在一起以形成记录。 Go支持在struct类型而非接口类型上定义的方法。
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)
}