问题描述
我阅读了许多类似的问题,但仍找不到正确的解决方案。希望有人能给我更好的主意。
我的错误响应可能是以下格式之一:
var errProxy = `{"errors":{"id": "1","message": "Failed to resolve the ip","status": "Failed"}}`
var errServer = `{"errors": "Failed to ping the dns server."}`
我正在尝试通过使用两个结构来解决此问题,并尝试一个接一个地解组直到err为nil并返回:
// ErrorServer and ErrorProxy is my two struct to represent my above two error response.
type ErrorServer struct {
Error string `json:"errors"`
}
type ErrorResponse struct {
ID string `json:"id"`
Message string `json:"message"`
Status string `json:"status"`
}
type ErrorProxy struct {
ErrorResponse
}
这是我用来解析它的函数:
func parseErrorResponse(body io.ReadCloser) (string,error) {
var errServer ErrorServer
var errProxy ErrorProxy
err := json.NewDecoder(body).Decode(&errServer)
if err != nil {
err = json.NewDecoder(body).Decode(&errProxy)
if err != nil {
return "",err
}
return errProxy.Error,nil
}
return errServer.Errors,nil
}
解决方法
我认为自定义解组功能对于这种情况非常有用
type ErrorServer struct {
Error string
}
type ErrorResponse struct {
ID string
Message string
Status string
}
type ErrorProxy struct {
Err ErrorResponse
}
func parseErrorResponse(body io.Reader) (interface{},error) {
data := make(map[string]interface{})
if err := json.NewDecoder(body).Decode(&data); err != nil {
return nil,err
}
// Check type of errors field
switch errors := data["errors"].(type) {
case string:
// Unmarshal for ErrorServer
errServer := &ErrorServer{
Error: errors,}
return errServer,nil
case map[string]interface{}:
// Unmarshal for ErrorProxy
errProxy := &ErrorProxy{
Err: ErrorResponse{
ID: errors["id"].(string),Message: errors["message"].(string),Status: errors["status"].(string),},}
return errProxy,nil
default:
return nil,fmt.Errorf(`failed to parse "errors" field`)
}
}
func main() {
body := bytes.NewReader([]byte(`{"errors": "failed to ping the dns server."}`))
//body := bytes.NewReader([]byte(`{"errors":{"id": "1","message": "failed to resolve the ip","status": "failed"}}`))
parsedErr,_ := parseErrorResponse(body)
switch err := parsedErr.(type) {
case *ErrorServer:
fmt.Printf("err server: %+v \n",err)
case *ErrorProxy:
fmt.Printf("err response: %+v \n",err)
}
}
,
另一种方法是使用类型断言。您可以将json字符串解组到map[string]interface{}
中,并检查值interface{}
是string
还是map[string]interface{}
。根据其类型,您会知道它是哪种错误,并从中构造出一个结构。
很有趣,我在这里给出了此问题的答案:使用自定义的UnmarshalJSON
函数。 How do you modify this struct in Golang to accept two different results?
适用于您的情况:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Answer struct {
Errors Error `json:"errors"`
}
type ErrorResponse struct {
ID string `json:"id"`
Message string `json:"message"`
Status string `json:"status"`
}
type Error struct {
Error string
ErrorResponse ErrorResponse
}
func (s *Error) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
// no data,nothing to do
return nil
}
if b[0] == '{' {
// is object
return json.Unmarshal(b,&s.ErrorResponse)
}
return json.Unmarshal(b,&s.Error)
}
func main() {
var errProxy = []byte(`{"errors":{"id": "1","status": "failed"}}`)
var errServer = []byte(`{"errors": "failed to ping the dns server."}`)
var answ Answer
if err := json.Unmarshal(errProxy,&answ); err != nil {
log.Fatal(err)
}
fmt.Println(answ)
answ = Answer{}
if err := json.Unmarshal(errServer,&answ); err != nil {
log.Fatal(err)
}
fmt.Println(answ)
}
上面示例中的键是包含两个变体的类型。我们还可以简化一下,因为两种错误都可能包含在ErrorResponse
类型中:
type Answer struct {
Errors ErrorResponse `json:"errors"`
}
type ErrorResponse struct {
ID string
Message string
Status string
}
func (s *ErrorResponse) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
// no data,nothing to do
return nil
}
if b[0] == '{' {
// is object
var tmp struct {
ID string `json:"id"`
Message string `json:"message"`
Status string `json:"status"`
}
if err := json.Unmarshal(b,&tmp); err != nil {
return err
}
s.ID = tmp.ID
s.Message = tmp.Message
s.Status = tmp.Status
return nil
}
return json.Unmarshal(b,&s.Message)
}
这里不需要Error
结构。