如何解压 golang 中的 grpc status.details 错误?
How can I unpack the grpc status.details error in golang?
我想为我的 REST API 使用 google.golang.org/grpc/status 错误模型,因为它说你可以:
Status
类型定义了适用于不同编程环境的逻辑错误模型,包括REST API和RPC API。
但是我 运行 遇到了结构的 details
部分的问题。我知道它是 []*anypb.Any
类型,但是,我不清楚如何将它变成“解压”形式,以便我可以看到 Field 和 Description 属性,而不是 base64 编码的 value
字段。
我得到的是:
{
"code": 3,
"message": "One or more fields are invalid",
"details": [
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"value": "CgVFbWFpbBIUSW52YWxpZCBlbWFpbCBmb3JtYXQ="
},
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"value": "CghQYXNzd29yZBIeTXVzdCBiZSBhdCBsZWFzdCAxMCBjaGFyYWN0ZXJz"
}
]
}
我应该得到什么:
{
"code": 3,
"message": "One or more fields are invalid",
"details": [
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"field": "Email",
"description": "Invalid email format"
},
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"field": "Password",
"description": "Must be at least 10 characters"
}
]
}
示例代码:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func main () {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
err := getError()
st, _ := status.FromError(err)
p:= st.Proto()
w.Header().Set("content-type","application/json")
err = json.NewEncoder(w).Encode(p)
if err !=nil {
fmt.Println("Error encoding", err)
}
})
http.ListenAndServe(":3000", r)
}
func getError() error {
st := status.New(codes.InvalidArgument, "One or more fields are invalid")
f1 := &errdetails.BadRequest_FieldViolation{
Field: "Email",
Description: "Invalid email format",
}
f2 := &errdetails.BadRequest_FieldViolation{
Field: "Password",
Description: "Must be at least 10 characters",
}
st, _ = st.WithDetails(f1)
st, _ = st.WithDetails(f2)
return st.Err()
}
json
编码器不是 100% 兼容 protobuf。
改为使用 "google.golang.org/protobuf/encoding/protojson"
中的 protojson.Marshal
。
看到这个Playground。
虽然没有那么快。
编辑要回答更快替代方案的请求:
可以利用自定义错误结构来保存所有必需的数据并手动解包 grpc 状态及其详细信息。看到这个 playground。在我的机器上,这节省了大约 15% 的时间。
我想为我的 REST API 使用 google.golang.org/grpc/status 错误模型,因为它说你可以:
Status
类型定义了适用于不同编程环境的逻辑错误模型,包括REST API和RPC API。
但是我 运行 遇到了结构的 details
部分的问题。我知道它是 []*anypb.Any
类型,但是,我不清楚如何将它变成“解压”形式,以便我可以看到 Field 和 Description 属性,而不是 base64 编码的 value
字段。
我得到的是:
{
"code": 3,
"message": "One or more fields are invalid",
"details": [
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"value": "CgVFbWFpbBIUSW52YWxpZCBlbWFpbCBmb3JtYXQ="
},
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"value": "CghQYXNzd29yZBIeTXVzdCBiZSBhdCBsZWFzdCAxMCBjaGFyYWN0ZXJz"
}
]
}
我应该得到什么:
{
"code": 3,
"message": "One or more fields are invalid",
"details": [
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"field": "Email",
"description": "Invalid email format"
},
{
"type_url": "type.googleapis.com/google.rpc.BadRequest.FieldViolation",
"field": "Password",
"description": "Must be at least 10 characters"
}
]
}
示例代码:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func main () {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
err := getError()
st, _ := status.FromError(err)
p:= st.Proto()
w.Header().Set("content-type","application/json")
err = json.NewEncoder(w).Encode(p)
if err !=nil {
fmt.Println("Error encoding", err)
}
})
http.ListenAndServe(":3000", r)
}
func getError() error {
st := status.New(codes.InvalidArgument, "One or more fields are invalid")
f1 := &errdetails.BadRequest_FieldViolation{
Field: "Email",
Description: "Invalid email format",
}
f2 := &errdetails.BadRequest_FieldViolation{
Field: "Password",
Description: "Must be at least 10 characters",
}
st, _ = st.WithDetails(f1)
st, _ = st.WithDetails(f2)
return st.Err()
}
json
编码器不是 100% 兼容 protobuf。
改为使用 "google.golang.org/protobuf/encoding/protojson"
中的 protojson.Marshal
。
看到这个Playground。
虽然没有那么快。
编辑要回答更快替代方案的请求:
可以利用自定义错误结构来保存所有必需的数据并手动解包 grpc 状态及其详细信息。看到这个 playground。在我的机器上,这节省了大约 15% 的时间。