在Web开发业务中,通常使用业务状态码来判断业务状态,不使用http状态码。在kratos V2中控制 http 的返回值,在 http 返回值外面返回自己熟悉的结构
在NewHTTPServer中进行使用(替换返回结构)
// 过滤,所包含的路由不会经过jwt权限验证
func NewSkipRoutersMatcher() selector.MatchFunc {
//完整 todo /包名.服务名/方法名
smn := "/intelligent_analysis.v1.Analysis" //包名.服务名
skipRouters := make(map[string]struct{})
skipRouters[smn+"/Login"] = struct{}{} //通过operation匹配规则,并不是http本身的路由 /包名.服务名/方法名
skipRouters[smn+"/Platform"] = struct{}{}
return func(ctx context.Context, operation string) bool {
if _, ok := skipRouters[operation]; ok {
return false
}
return true
}
}
/=================================================================
// NewHTTPServer new a HTTP server.
func NewHTTPServer(c *conf.Server, jwtc *conf.JWT, cloud_platform *service.AnalysisService, logger log.Logger) *http.Server {
var opts = []http.ServerOption{
//自定义返回错误结构
http.ErrorEncoder(errorEncoder), //替代默认的错误结构
//自定义返回数据结构
http.ResponseEncoder(responseEncoder), //替代默认的返回数据结构
http.Middleware(
recovery.Recovery(),
selector.Server(auth.JWTAuth(jwtc.Secret)).Match(NewSkipRoutersMatcher()).Build(),
logging.Server(logger),
//cors.MiddlewareCors(), //跨域中间件
),
http.Filter(
//跨域 推荐
handlers.CORS(
handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}),
handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS", "DELETE"}),
handlers.AllowedOrigins([]string{"*"}),
)),
}
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...)
v1.RegisterAnalysisHTTPServer(srv, cloud_platform)
return srv
}
返回结构的具体实现如下:
type ResponseError struct {
Code int `json:"code"`
Message string `json:"message"`
}
func (e *ResponseError) Error() string {
return fmt.Sprintf("ResponseError: %d", e.Code)
}
func NewResponseError(code int, message string) *ResponseError {
return &ResponseError{
Code: code,
Message: message,
}
}
// FromError try to convert an error to *ResponseError.
func FromError(err error) *ResponseError {
if err == nil {
return nil
}
if se := new(errors.Error); errors.As(err, &se) {
return NewResponseError(int(se.Code), se.Message)
}
return &ResponseError{Code: 500}
}
//自定义返回error
func errorEncoder(w nethttp.ResponseWriter, r *nethttp.Request, err error) {
se := errors.FromError(err)
codec, _ := http.CodecForRequest(r, "Accept")
body, err := codec.Marshal(se)
if err != nil {
w.WriteHeader(500)
return
}
w.Header().Set("Content-Type", "application/"+codec.Name())
//w.WriteHeader(se.Code) //写入状态码中,在此不需要
_, _ = w.Write(body)
}
-----------------------------------
//自定义返回数据结构
func responseEncoder(w http.ResponseWriter, r *http.Request, data interface{}) error {
type Response struct {
Code int `json:"code"`
Data interface{} `json:"data"`
Message string `json:"message"`
}
///************************************
//Code与Message直接写固定值
res := &Response{
Code: 200,
Data: data,
Message: "成功",
}
///**********************************/
//codec := encoding.GetCodec("json") //这两行的目的就是为了把要返回的数据进行序列化
//msRes, err := codec.Marshal(res) //也可采用上面函数errorEncoder中的方法或者下面的直接JSON序列化
msRes, err := json.Marshal(res)
if err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
w.Write(msRes)
return nil
}
跨域中间件
前端需要将withCredentials设置为 false
// MiddlewareCors 设置跨域请求头
func MiddlewareCors() middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (interface{}, error) {
if tr, ok := transport.FromServerContext(ctx); ok {
//tr.ReplyHeader().Set("Access-Control-Allow-Origin", "*")
//tr.ReplyHeader().Set("Access-Control-Allow-Credentials", "true")
//tr.ReplyHeader().Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,PATCH,DELETE")
//tr.ReplyHeader().Set("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,Authorization")
if ht, ok := tr.(http.Transporter); ok {
origin := ht.RequestHeader().Get("Origin")
method := ht.Request().Method
if method == nethttp.MethodOptions {
ht.ReplyHeader().Set("Access-Control-Allow-Origin", origin) //origin也可以替换为 *
ht.ReplyHeader().Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,PATCH,DELETE")
ht.ReplyHeader().Set("Access-Control-Allow-Credentials", "true")
ht.ReplyHeader().Set("Access-Control-Allow-Headers", "Content-Type, X-Requested-With,Authorization")
}
}
}
return handler(ctx, req)
}
}
}
//func NotFoundHandler(res nethttp.ResponseWriter, req *nethttp.Request) {
// res.Header().Set("Access-Control-Allow-Origin", "*")
// res.Header().Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,PATCH,DELETE")
// res.Header().Set("Access-Control-Allow-Credentials", "true")
// res.Header().Set("Access-Control-Allow-Headers", "Content-Type,"+
// "X-Requested-With,Access-Control-Allow-Credentials,User-Agent,Content-Length,Authorization")
//
// log.Info("NotFoundHandler")
//
// errCode := errors.NotFound("page not found", "page not found")
// buffer, _ := json.Marshal(errCode)
// //res.WriteHeader(400)
// _, _ = res.Write(buffer)
//}