承接上文《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的话,如果返回值没有,则直接判断空即可。做出来的效果非常不错,少些很多代码。
最后按照惯例,附上本案例的源码,登陆后即可下载。










还没有评论,来说两句吧...