goでSockjsを使用していますが、JavaScriptクライアントがサーバーにjsonを送信すると、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
最初にJSON文字列に:)
例はこちら 、@ 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エンコードが2回行われています。生成を実行しているコードを修正して、1回だけ発生するようにします。
何が起こっているかを示す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\"}"
クレイジー・トレインが指摘したように、あなたの入力は二重にエスケープされているようで、問題を引き起こしています。これを修正する1つの方法は、関数session.ReadMessasge()
が適切にエスケープされた適切な出力を返すことを確認することです。ただし、それが不可能な場合は、x3roが提案したことをいつでも実行して、golang関数strconv.Unquote
を使用できます。
これが実際の遊び場の例です。
時々、 strconv.Unquote
は機能しません。
例は問題と私の解決策を示しています。 (遊び場リンク: https://play.golang.org/p/Ap0cdBgiA05 )
@Crazy Trainの「2回エンコードする」というアイデアに感謝します。2回デコードしました...
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)
}
JavaScriptから悪名高いエスケープ文字列の落とし穴に陥りました。 JSON文字列をjson.Marshalでシリアル化するときに、Goで同じ問題に直面することがよくあります(例:)。
in := `{"firstName":"John","lastName":"Dow"}` bytes, err := json.Marshal(in)
json.Marshalは二重引用符をエスケープし、構造体にバイトを非整列化しようとするときに同じ問題を生成します。
Goで問題が発生した場合は、問題の詳細と解決策を記載した GolangでJSON文字列を正しくシリアル化する方法 の投稿をご覧ください。
問題に示されるデータは、いくつかの目的のために文字列化されています。場合によっては、jsonの改行を表す文字列に\ nを含めることもできます。
次の例を使用して、この種のデータを非整列化/逆シリアル化する最も簡単な方法を理解しましょう。
次の行は、ソースから取得し、逆シリアル化するデータを示しています
stringifiedData:= "{\ r\n \" a\":\" b\"、\ r\n \" c\":\" d\"\ r\n}"
今、最初にすべての新しい行を削除します
stringifiedData = strings.ReplaceAll(stringifiedData、 "\ n"、 "")
次に、文字列にある余分な引用符をすべて削除します
stringifiedData = strings.ReplaceAll(stringifiedData、 "\\" "、"\"")
文字列をバイト配列に変換しましょう
dataInBytes:= [] byte(stringifiedData)
非整列化を行う前に、データの構造を定義しましょう
jsonObject:=&struct {
文字列 `json:" a "`
C文字列 `json:" c "`
}
これで、値をjsonObjectに逆シリアル化できます
json.Unmarshal(dataInBytes、jsonObject)}