利用json.RawMessage来动态反序列化

当你在WebSocket编程时,你会在同一个WebSocket连接上发送和接收各种不同的消息。
当你这样做时,您经常会遇到反序列化不同类型消息的问题。
例如作为WebSocket服务器,我们要发送两种类型的消息:

    type MessageTypeA struct {
        Name  string `json:"name"`
        Place string `json:"place"`
    }

    type MessageTypeB struct {
        Animal string `json:"animal"`
        Thing  string `json:"thing"`
    }

要发送这些消息,您需要封送这些结构。
并在WebSocket连接上写入这些字节。代码应该类似于:

    messageA := MessageTypeA { Name:  "Pankhudi", Place: "India"}
    // OR
    messageB := MessageTypeB { Animal: "dog", Thing:  "cap"}

    bytes, err := json.Marshal(messageA) // OR messageB 
    err = websocketConn.WriteMessage(websocket.TextMessage, bytes)

现在,WebSocket客户端的反序列化逻辑事先不知道它将接收什么类型的消息,所以只好每个都尝试一次。

    bytes, _, err := websocketConn.Read()
    if err != nil {...}

    messageA := MessageTypeA{}
    // OR
    messageB := MessageTypeB{}

    json.Unmarshal(dataBytes, &messageA)
    // OR
    json.Unmarshal(dataBytes, &messageA)

我如何知道要用哪一个结构体来反序列化?json.RawMessage来拯救我们!
在服务器上,让我们创建一个MessageWrapperA结构体,并引入名为MessageType的附加属性,并将实际消息作为“Content”之类的泛型

    type MessageWrapperA struct {
        MessageType  string `json:"message_type"`
        MessageTypeA `json:"content"`
    }
    messageA := MessageWrapperA{
        MessageType:  "A",
        MessageTypeA: MessageTypeA{Name: "Pankhudi", Place: "India"},
    }
    bytes, _ := json.Marshal(messageA)

然后在客户端我们可以用MessageWrapper结构体先解码,得到MessageType,再根据MessageType来选择具体的结构体二次反序列化即可,代码如下:

    type MessageWrapper struct {
        MessageType string          `json:"message_type"`
        Content     json.RawMessage `json:"content"`
    }
    dataBytes, _, err  :=  wsutil.ReadServerData(conn)
    _ = json.Unmarshal(dataBytes, &messageWrapper)
    if messageWrapper.MessageType == "A" {
        subMessage := MessageTypeA{}
        _ = json.Unmarshal(messageWrapper.Content, &subMessage)
        println(subMessage.Name, subMessage.Place)
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 2

请问你前端定义的 type MessageWrapper struct { MessageType string json:"message_type" Content json.RawMessage json:"content" } MessageWrapper 中 Content 的序列化采用的是?Content 数据类型是Uint8Array ?

1年前 评论
xing393939 (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!