Golang中如何将字符串输入映射到任意JSON结构
Go Playground - Go 编程语言
谢谢,它起作用了。
更多关于Golang中如何将字符串输入映射到任意JSON结构的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好 @Saral_Sharma,
游乐场中的代码无法编译。在移除了 body 字符串内的两个反引号后,代码可以编译并产生以下输出:
Hello GO
erro101
invalid character 't' after object key:value pair
2009/11/10 23:00:00 Operation:
erro102
invalid json body provided for the request
这就是你为此主题所提及的错误信息吗?
感谢您的解释,所以您希望将JSON数据解组到结构体中,但保留部分数据作为字符串。
您能控制输入数据吗?如果将defaultResponse对象的值包装成字符串,它将保持为字符串而不会被进一步解组。
"defaultResponse”: "{\“title\”:\“Buy cheese and bread for breakfast.\”}"

type AddEndpointRequest struct {
Method string `json:"method"`
Path string `json:"path"`
ContentType int `json:"contentType"`
DefaultWaitTimeInMillis int64 `json:"defaultWaitTimeInMillis"`
DefaultStatusCode int `json:"defaultStatusCode"`
DefaultResponse string `json:"defaultResponse"`
Filters []EndpointFilterRequest `json:"filters"`
}
我希望将 defaultResponse 属性作为 JSON 字符串传递。
如果我传递这个:"defaultResponse":{"title":"Buy cheese and bread for breakfast."}
会收到错误:json: cannot unmarshal object into Go struct field AddEndpointRequest.defaultResponse of type string
所以,我希望将 defaultResponse 属性作为字符串传递,稍后再将其映射为 JSON 对象,但失败了。
body := `{"method":"GET","path":"/getMMEPicks/","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":{"title":"Buy cheese and bread for breakfast."},"filters":[{"headerParams":{"contentType":"application/json","userid":"s0s024v"},"queryParams":{"pagesize":"2000","status":"all"},"pathParams":{"countryCode":"US","store":"2686"},"body":"hello","waitTimeInMillis":100,"statusCode":200,"response":"200"}]}`
我进一步尝试简化查询。
在这里,我想将 DefaultResponse 作为字符串接收,但之后在映射到任何 JSON 结构体之前,验证它是否是有效的 JSON。
包含验证的完整代码可以在这里找到: Go Playground - The Go Programming Language
type AddEndpointRequest struct {
Method string `json:"method"`
ContentType int `json:"contentType"`
DefaultStatusCode int `json:"defaultStatusCode"`
DefaultResponse string `json:"defaultResponse"`
}
我尝试了不同的选项,但都不起作用。
-
如果我传入这个:
"defaultResponse":{"title":"Buy cheese and bread for breakfast."}会得到错误:json: cannot unmarshal object into Go struct field AddEndpointRequest.defaultResponse of type string -
body :=
{"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"[{"p":"k"}]"}错误:
invalid character 'p' after object key:value pair -
body :=
{"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{“p”:“k”}"}./prog.go:21:117: syntax error: unexpected { at end of statement -
body :=
{"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{/"p/":/"k/"}“}Error : ./prog.go:21:130: syntax error: unexpected literal "}” at end of statement
还有更多尝试。
在Golang中处理动态JSON结构时,可以使用json.RawMessage或interface{}来延迟解析。以下是两种实现方式:
方法1:使用json.RawMessage
package main
import (
"encoding/json"
"fmt"
)
type Response struct {
Status int `json:"status"`
Data json.RawMessage `json:"data"`
Message string `json:"message"`
}
func main() {
// 示例1:data字段为字符串
jsonStr1 := `{"status":200,"data":"success","message":"操作成功"}`
// 示例2:data字段为对象
jsonStr2 := `{"status":200,"data":{"id":1,"name":"test"},"message":"操作成功"}`
// 示例3:data字段为数组
jsonStr3 := `{"status":200,"data":[1,2,3],"message":"操作成功"}`
var resp Response
// 解析字符串类型的data
json.Unmarshal([]byte(jsonStr1), &resp)
fmt.Printf("字符串类型: %s\n", resp.Data)
// 解析对象类型的data
json.Unmarshal([]byte(jsonStr2), &resp)
fmt.Printf("对象类型: %s\n", resp.Data)
// 解析数组类型的data
json.Unmarshal([]byte(jsonStr3), &resp)
fmt.Printf("数组类型: %s\n", resp.Data)
}
方法2:使用interface{}进行动态解析
package main
import (
"encoding/json"
"fmt"
)
type DynamicResponse struct {
Status int `json:"status"`
Data interface{} `json:"data"`
Message string `json:"message"`
}
func main() {
jsonInput := `{"status":200,"data":{"user":"john","age":30},"message":"success"}`
var resp DynamicResponse
json.Unmarshal([]byte(jsonInput), &resp)
// 根据实际类型处理data字段
switch v := resp.Data.(type) {
case string:
fmt.Printf("字符串类型: %s\n", v)
case map[string]interface{}:
fmt.Printf("对象类型: %v\n", v)
// 可以进一步访问具体字段
if user, ok := v["user"]; ok {
fmt.Printf("用户名: %s\n", user)
}
case []interface{}:
fmt.Printf("数组类型: %v\n", v)
default:
fmt.Printf("未知类型: %v\n", v)
}
}
方法3:自定义UnmarshalJSON实现
package main
import (
"encoding/json"
"fmt"
)
type FlexibleData struct {
Value interface{}
}
func (f *FlexibleData) UnmarshalJSON(data []byte) error {
// 先尝试解析为字符串
var str string
if err := json.Unmarshal(data, &str); err == nil {
f.Value = str
return nil
}
// 再尝试解析为对象
var obj map[string]interface{}
if err := json.Unmarshal(data, &obj); err == nil {
f.Value = obj
return nil
}
// 最后尝试解析为数组
var arr []interface{}
if err := json.Unmarshal(data, &arr); err == nil {
f.Value = arr
return nil
}
return json.Unmarshal(data, &f.Value)
}
type CustomResponse struct {
Status int `json:"status"`
Data FlexibleData `json:"data"`
Message string `json:"message"`
}
func main() {
inputs := []string{
`{"status":200,"data":"string value","message":"ok"}`,
`{"status":200,"data":{"key":"value"},"message":"ok"}`,
`{"status":200,"data":[1,2,3],"message":"ok"}`,
}
for _, input := range inputs {
var resp CustomResponse
json.Unmarshal([]byte(input), &resp)
fmt.Printf("解析结果: %T %v\n", resp.Data.Value, resp.Data.Value)
}
}
实际应用示例
package main
import (
"encoding/json"
"fmt"
)
type APIResponse struct {
Success bool `json:"success"`
Code int `json:"code"`
Result json.RawMessage `json:"result"`
Error string `json:"error,omitempty"`
}
// 定义可能的数据结构
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
type Product struct {
ID int `json:"id"`
Price float64 `json:"price"`
}
func main() {
// 模拟API返回的不同类型数据
responses := []string{
// 用户数据
`{"success":true,"code":200,"result":{"id":1,"name":"Alice"}}`,
// 产品数据
`{"success":true,"code":200,"result":{"id":101,"price":29.99}}`,
// 字符串消息
`{"success":true,"code":200,"result":"操作成功"}`,
// 数组数据
`{"success":true,"code":200,"result":[1,2,3,4,5]}`,
}
for _, respStr := range responses {
var apiResp APIResponse
json.Unmarshal([]byte(respStr), &apiResp)
// 根据业务逻辑决定如何解析result
if len(apiResp.Result) > 0 && apiResp.Result[0] == '{' {
// 尝试解析为User
var user User
if err := json.Unmarshal(apiResp.Result, &user); err == nil && user.ID > 0 {
fmt.Printf("用户数据: %+v\n", user)
continue
}
// 尝试解析为Product
var product Product
if err := json.Unmarshal(apiResp.Result, &product); err == nil && product.ID > 0 {
fmt.Printf("产品数据: %+v\n", product)
continue
}
}
// 其他情况直接输出原始JSON
fmt.Printf("原始数据: %s\n", apiResp.Result)
}
}
这些方法允许你在保持类型安全的同时,灵活处理不同结构的JSON数据。json.RawMessage在需要延迟解析或根据条件解析时特别有用,而interface{}提供了最大的灵活性但需要类型断言。

