英文:
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).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论