我在 Go 中使用 Sockjs,但是当 JavaScript 客户端将 json 发送到服务器时,它会对它进行转义,并将其作为 [] 字节发送。我正在尝试弄清楚如何解析 json,以便我可以读取数据。但我收到这个错误。
json:无法将字符串解组为 main.Msg 类型的 Go 值
我该如何解决这个问题?
html.UnescapeString()
没有效果。
val, err := session.ReadMessage()
if err != nil {
break
}
var msg Msg
err = json.Unmarshal(val, &msg)
fmt.Printf("%v", val)
fmt.Printf("%v", err)
type Msg struct {
Channel string
Name string
Msg string
}
//Output
"{\"channel\":\"buu\",\"name\":\"john\", \"msg\":\"doe\"}"
json: cannot unmarshal string into Go value of type main.Msg
strconv.Unquote
:)
这是一个示例,由@gregghz 提供:
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Msg struct {
Channel string
Name string
Msg string
}
func main() {
var msg Msg
var val []byte = []byte(`"{\"channel\":\"buu\",\"name\":\"john\", \"msg\":\"doe\"}"`)
s, _ := strconv.Unquote(string(val))
err := json.Unmarshal([]byte(s), &msg)
fmt.Println(s)
fmt.Println(err)
fmt.Println(msg.Channel, msg.Name, msg.Msg)
}
您需要在生成 JSON 的代码中修复此问题。
当它被格式化为这样时,它被 JSON 编码了两次。修复正在生成的代码,使其仅发生一次。
这是一些 JavaScript,显示了正在发生的事情。
// Start with an object
var object = {"channel":"buu","name":"john", "msg":"doe"};
// serialize once
var json = JSON.stringify(object); // {"channel":"buu","name":"john","msg":"doe"}
// serialize twice
json = JSON.stringify(json); // "{\"channel\":\"buu\",\"name\":\"john\",\"msg\":\"doe\"}"
有时,
strconv.Unquote
不起作用。
这里有一个例子展示了问题和我的解决方案。 (游乐场链接:https://play.golang.org/p/Ap0cdBgiA05)
感谢@Crazy Train 的“编码两次”想法,我刚刚解码了两次......
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Wrapper struct {
Data string
}
type Msg struct {
Photo string
}
func main() {
var wrapper Wrapper
var original = `"{\"photo\":\"https:\/\/www.abc.net\/v\/t1.0-1\/p320x320\/123.jpg\"}"`
_, err := strconv.Unquote(original)
fmt.Println(err)
var val []byte = []byte("{\"data\":"+original+"}")
fmt.Println(string(val))
err = json.Unmarshal([]byte(val), &wrapper)
fmt.Println(wrapper.Data)
var msg Msg
err = json.Unmarshal([]byte(wrapper.Data), &msg)
fmt.Println(msg.Photo)
}
正如 Crazy Train 所指出的,您的输入似乎被双重转义,从而导致了问题。解决此问题的一种方法是确保函数
session.ReadMessasge()
返回正确转义的正确输出。但是,如果不可能,您始终可以按照 x3ro 的建议进行操作并使用 golang 函数strconv.Unquote
。
这是一个操场示例:
问题中显示的数据出于某些目的而被字符串化,在某些情况下您甚至可以拥有 在字符串中代表 json 中的换行符。
让我们使用以下示例了解解组/反序列化此类数据的最简单方法:
下一行显示您从源获取并想要反序列化的数据
字符串化数据:=“{ \"a\": \"b\", \“光盘\” }“
现在,首先删除所有新行
stringifiedData = strings.ReplaceAll(stringifiedData, " ”、“”)
然后删除字符串中存在的所有额外引号
stringifiedData = strings.ReplaceAll(stringifiedData, "\"", "\"")
现在让我们将字符串转换为字节数组
dataInBytes := []byte(stringifiedData)
在进行解组之前,让我们定义数据的结构
jsonObject := &struct{
字符串 `json:"a"`
C 字符串 `json:"c"`
}
现在,您可以将值反序列化为 jsonObject
json.Unmarshal(dataInBytes, jsonObject)}
这是我的解决方案:https://go.dev/play/p/iLUCgUFIyKk 它基于 @semicircle21 的解决方案,但不需要额外的 Wrapper 结构体,go json 包可以直接解组为字符串。
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Msg struct {
Photo string
}
func main() {
var original = `"{\"photo\":\"https:\/\/www.abc.net\/v\/t1.0-1\/p320x320\/123.jpg\"}"`
_, err := strconv.Unquote(original)
fmt.Println(err)
var data string
err = json.Unmarshal([]byte(original), &data)
fmt.Println(data)
var msg Msg
err = json.Unmarshal([]byte(data), &msg)
fmt.Println(msg.Photo)
}
您陷入了 JavaScript 中臭名昭著的 escaped string 陷阱。当使用 json.Marshal 序列化 JSON 字符串时,人们经常在 Go 中面临(就像我一样)同样的问题,例如:
in := `{"firstName":"John","lastName":"Dow"}`
bytes, err := json.Marshal(in)
json.Marshal 转义双引号,当您尝试将字节解组到结构中时会产生相同的问题。
如果您在 Go 中遇到问题,请查看 How To Correctly Serialize JSON String In Golang 帖子,其中详细描述了该问题及其解决方案。