Go如何接收JSON字符串输入 校验后按条件转换为目标对象
需求说明
需要将结构体AddEndpointRequest中的DefaultResponse字段先以字符串类型接收,校验字段内容是否为合法JSON后,再映射到对应的JSON结构体。
初始使用的结构体定义如下:
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 - 尝试用反引号拼接嵌套JSON定义body时,出现Go语法错误:
./prog.go:21:117: syntax error: unexpected { at end of statement - 尝试加斜杠转义嵌套JSON定义body时,出现Go语法错误:
./prog.go:21:130: syntax error: unexpected literal "}" at end of statement - 其余多种写法也均未解决问题。
问题原因
- JSON类型不匹配:当请求中
defaultResponse传的是对象、数组等非字符串类型JSON值时,Go标准库encoding/json默认不支持直接反序列化到string类型字段,会抛出类型不匹配错误。 - JSON格式错误:手写JSON字符串时,字符串值内部的双引号未做转义,会导致JSON解析器提前判定字符串结束,后续内容解析失败。
- Go语法错误:使用反引号定义原始字符串时,若拼接逻辑不合法、或未正确处理特殊字符,会触发编译阶段的语法错误。
解决方案
通过自定义JSON反序列化类型,实现任意JSON值到字符串的接收,同时保留合法性校验、二次映射能力,避免手写JSON转义问题。
完整实现代码
package main import ( "encoding/json" "fmt" ) // RawJSONString 支持接收任意合法JSON值,存储为原始字符串格式 type RawJSONString string // UnmarshalJSON 实现自定义反序列化逻辑,直接存储原始JSON字节 func (s *RawJSONString) UnmarshalJSON(data []byte) error { *s = RawJSONString(data) return nil } // IsValidJSON 校验当前存储内容是否为合法JSON func (s RawJSONString) IsValidJSON() bool { return json.Valid([]byte(s)) } // 修改后的请求结构体,DefaultResponse使用自定义类型 type AddEndpointRequest struct { Method string `json:"method"` ContentType int `json:"contentType"` DefaultStatusCode int `json:"defaultStatusCode"` DefaultResponse RawJSONString `json:"defaultResponse"` } func main() { // 示例1:defaultResponse传JSON对象 body1 := `{"method":"GET","contentType":1,"defaultStatusCode":200,"defaultResponse":{"title":"Buy cheese and bread for breakfast."}}` var req1 AddEndpointRequest if err := json.Unmarshal([]byte(body1), &req1); err != nil { panic(err) } fmt.Println("=== 传JSON对象场景 ===") fmt.Printf("原始字符串内容: %s\n", req1.DefaultResponse) fmt.Printf("是否为合法JSON: %v\n", req1.DefaultResponse.IsValidJSON()) // 二次映射到对应结构体 type RespStruct struct { Title string `json:"title"` } var data1 RespStruct if err := json.Unmarshal([]byte(req1.DefaultResponse), &data1); err != nil { panic(err) } fmt.Printf("二次映射结果: %+v\n\n", data1) // 示例2:defaultResponse传JSON数组 body2 := `{"method":"GET","contentType":1,"defaultStatusCode":200,"defaultResponse":[{"p":"k"}]}` var req2 AddEndpointRequest if err := json.Unmarshal([]byte(body2), &req2); err != nil { panic(err) } fmt.Println("=== 传JSON数组场景 ===") fmt.Printf("原始字符串内容: %s\n", req2.DefaultResponse) fmt.Printf("是否为合法JSON: %v\n", req2.DefaultResponse.IsValidJSON()) // 二次映射到切片 var data2 []map[string]string if err := json.Unmarshal([]byte(req2.DefaultResponse), &data2); err != nil { panic(err) } fmt.Printf("二次映射结果: %+v\n", data2) }
注意事项
- 若需要将JSON内容作为字符串值传递(而非直接传对象/数组),手写JSON时必须对字符串内部的双引号做转义,例如
"defaultResponse":"[{\"p\":\"k\"}]",否则会触发JSON解析错误。 - 尽量避免手写拼接JSON字符串,优先通过结构体序列化生成请求体,可以彻底避免转义类错误。
内容的提问来源于stack exchange,提问作者RuntimeTerror
相关产品推荐
相关产品推荐

