Golang错误类型在编码为JSON时为空。

huangapple go评论161阅读模式
英文:

Golang Error Types are empty when encoded to JSON

问题

我正在尝试为一个 REST API 编码一些 JSON,除了一些错误之外,一切都正常。例如,使用以下结构体进行编码:

type TemplateResponse struct {
    Message  string
    Error    error
    Template Template
}

使用以下数据进行编码:

res := TemplateResponse{"Template not found.", fmt.Errorf("There is no template on this host with the name " + vars["name"]), Template{}}
json.NewEncoder(w).Encode(res)

返回结果如下:

{
  "Message": "Template not found.",
  "Error": {},
  "Template": {
    "Name": "",
    "Disabled": false,
    "Path": "",
    "Version": ""
  }
}

我在整个应用程序中似乎随机遇到这个问题,其中返回的 "error" 类型为空。有什么想法吗?

谢谢!

英文:

I'm trying to encode some JSON for a REST api, everything is working fine except for some errors. For example, with this struct:

type TemplateResponse struct {
	Message string
	Error   error
	Template Template
}

Encoded with this data:

res := TemplateResponse{"Template not found.", fmt.Errorf("There is no template on this host with the name " + vars["name"]), Template{}}
json.NewEncoder(w).Encode(res)

Returns:

{
  "Message": "Template not found.",
  "Error": {},
  "Template": {
    "Name": "",
    "Disabled": false,
    "Path": "",
    "Version": ""
  }
}

I'm getting this seemingly randomly across my application, where 'error' types are being returned as empty. Any ideas?

Thanks!

答案1

得分: 32

因为error只是一个接口。它可以持有任何实现该接口的具体类型的值。

在你的例子中,你使用fmt.Errorf()创建了一个error值。它调用了errors.New(),该函数返回一个指向未导出的errors.errorString结构体值的指针。它的定义如下:

type errorString struct {
  	s string
}

这个结构体值将被编组,但由于它没有导出字段(只有导出字段才会被编组),它将成为空的JSON对象:{}

"修复"的方法是:不要编组"通用"接口的值,依赖于动态值可以有意义地编组为JSON。相反,你应该添加一个字段来存储错误字符串(即error.Error()的结果),并且在编组时省略Error error字段,例如:

type TemplateResponse struct {
	Message  string
	Error    error `json:"-"`
	ErrorMsg string
	Template Template
}

当然,在编组之前,你还需要设置/填充ErrorMsg字段。

或者,如果你不需要在结构体中存储error值,可以完全删除该字段:

type TemplateResponse struct {
	Message  string
	ErrorMsg string
	Template Template
}

如果你仍然想保留Error error字段(而不是ErrorMsg字段),那么你需要通过实现json.Marshaler接口来实现自定义的编组逻辑,在这里你可以将error值"转换"为有意义的string(或者转换为其他可以正确编组的值)。

英文:

Because error is just an interface. It may hold a value of any concrete type that implements it.

In your example you used fmt.Errorf() to create an error value. That calls errors.New() which returns a pointer to a value of the unexported errors.errorString struct. Its definition is:

type errorString struct {
  	s string
}

This struct value will be marshaled, but since it has no exported fields (only exported fields are marshaled), it will be an empty JSON object: {}.

The "fix" is: don't marshal values of "general" interfaces, relying on that the dynamic values can be marshaled into JSON meaningfully. Instead you should add a field that stores the error string (the result of error.Error()), and omit the Error error field from marshaling, e.g.:

type TemplateResponse struct {
	Message  string
	Error    error `json:"-"`
	ErrorMsg string
	Template Template
}

Of course then you also need to set / fill the ErrorMsg field before marshaling.

Or if you don't need to store the error value in the struct, remove that field completely:

type TemplateResponse struct {
	Message  string
	ErrorMsg string
	Template Template
}

If you still want to keep the Error error field (and not the ErrorMsg field), then you need to implement a custom marshaling logic by implementing the json.Marshaler interface where you can "convert" the error value to a meaningful string for example (or into another value that can be marshaled properly).

huangapple
  • 本文由 发表于 2017年7月9日 03:17:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/44989924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定