承接上文《kratos微服务实战(十七)kratos项目之全局错误处理》,在前面我们定义了一个BaseResponse的json返回格式,他主要应用于错误类的返回,这里我们再实现正确的信息返回也统一使用这个格式。即统一全局的返回格式。
要实现全局的统一json返回格式,和上面的做法是一致的,即注册中间件,这里使用到的中间件是:http.ResponseEncoder。更改的地方还是internal/server/http.go文件的NewHTTPServer方法。
注入新的response中间件的代码如下:
http.ResponseEncoder(func(writer httpNet.ResponseWriter, request *httpNet.Request, i interface{}) error { reply := &http2.BaseResponse{ Code: 200, Msg: "请求成功", Data: i, } codec := encoding.GetCodec("json") data, _ := codec.Marshal(reply) writer.Header().Set("Content-Type", "application/json") writer.Write(data) return nil }),
此时http.go的完整代码如下:
package server import ( "encoding/json" "github.com/go-kratos/kratos/v2/encoding" "github.com/go-kratos/kratos/v2/middleware/logging" mmd "github.com/go-kratos/kratos/v2/middleware/metadata" "github.com/go-kratos/kratos/v2/middleware/validate" "github.com/go-kratos/swagger-api/openapiv2" httpNet "net/http" v2 "user-center/api/account/v1" v1 "user-center/api/helloworld/v1" http2 "user-center/internal/biz/http" "user-center/internal/conf" "user-center/internal/service" "github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/middleware/recovery" "github.com/go-kratos/kratos/v2/transport/http" ) // NewHTTPServer new an HTTP server. func NewHTTPServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger, account *service.AccountService) *http.Server { var opts = []http.ServerOption{ http.Middleware( validate.Validator(), logging.Server(log.DefaultLogger), mmd.Client(), recovery.Recovery(), ), http.ErrorEncoder( func(writer httpNet.ResponseWriter, request *httpNet.Request, err error) { log.Infof("拦截到的错误信息是:%s", err.Error()) message := extractMessageFromError(err) reply := &http2.BaseResponse{ Code: 400, Msg: message, Data: nil, } codec := encoding.GetCodec("json") data, _ := codec.Marshal(reply) writer.Header().Set("Content-Type", "application/json") writer.Write(data) }), http.ResponseEncoder(func(writer httpNet.ResponseWriter, request *httpNet.Request, i interface{}) error { reply := &http2.BaseResponse{ Code: 200, Msg: "请求成功", Data: i, } codec := encoding.GetCodec("json") data, _ := codec.Marshal(reply) writer.Header().Set("Content-Type", "application/json") writer.Write(data) return nil }), } if c.Http.Network != "" { opts = append(opts, http.Network(c.Http.Network)) } if c.Http.Addr != "" { opts = append(opts, http.Address(c.Http.Addr)) } if c.Http.Timeout != nil { opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) } srv := http.NewServer(opts...) handler := openapiv2.NewHandler() srv.HandlePrefix("/q/", handler) v1.RegisterGreeterHTTPServer(srv, greeter) v2.RegisterAccountHTTPServer(srv, account) return srv } func extractMessageFromError(err error) string { marshal, err2 := json.Marshal(err) if err2 != nil { return "系统错误" } var em ErrorMessage e := json.Unmarshal(marshal, &em) if e != nil { return "系统错误" } return em.Message } type ErrorMessage struct { Message string `json:"message"` }
咱们把项目运行起来看看:
是不是全部统一返回了格式,这里把login返回的代码包装到了这里的data里面。是不是非常方便。
备注:
1、这里的http.ResponseEncoder中间件只能接收http.status=200的返回值,不能接收非200的返回值,所以这里是接收不到错误的response返回的。
2、再grpc上我们定义了这种统一返回格式,那么就不需要在.proto文件中进行code和msg的定义了,直接使用pojo对象进行定义,兼容grpc的话,如果返回值没有,则直接判断空即可。做出来的效果非常不错,少些很多代码。
最后按照惯例,附上本案例的源码,登陆后即可下载。
还没有评论,来说两句吧...