go-zero中统一返回前端数据格式的几种方式

方式一、直接定义一个成功和失败的方法,在代码里面修改(对代码有侵入,每次都要修改代码)
  • 1、封装一个统一返回的方法

    go 复制代码
    package utils
    
    import (
    	"github.com/zeromicro/go-zero/rest/httpx"
    	"net/http"
    )
    
    type Body struct {
    	Code    int         `json:"code"`
    	Message string      `json:"message"`
    	Result  interface{} `json:"result,omitempty"`
    }
    
    func Response(w http.ResponseWriter, code int, message string, data interface{}) {
    	httpx.OkJson(w, Body{
    		Code:    code,
    		Message: message,
    		Result:  data,
    	})
    }
    
    // Success 成功的请求
    func Success(w http.ResponseWriter, data interface{}) {
    	Response(w, 0, "请求成功", data)
    }
    
    // Fail 失败的请求
    func Fail(w http.ResponseWriter, message string) {
    	Response(w, 1, message, nil)
    }
  • 2、修改代码的返回值方法调用

    go 复制代码
    func GetTestHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    	return func(w http.ResponseWriter, r *http.Request) {
    		l := demo.NewGetTestLogic(r.Context(), svcCtx)
    		resp, err := l.GetTest()
    		if err != nil {
    			//httpx.ErrorCtx(r.Context(), w, err)
    			utils.Fail(w, err.Error())
    		} else {
    			//httpx.OkJsonCtx(r.Context(), w, resp)
    			utils.Success(w, resp)
    		}
    	}
    }
方式二、在api文件定义的时候直接返回的数据结构(在定义api的时候繁琐了)
  • 1、api文件中定义

    properties 复制代码
    type Response {
    	Code string      `json:"code"`
    	Msg  string      `json:"msg"`
    	Data interface{} `json:"data"`
    }
    
    @server (
    	prefix: demo/v1
    	group:  demo
    )
    service demo-api {
    
    	@doc "测试"
    	@handler GetTest
    	get /testApi returns (Response)
    
    }
  • 2、在每次操作的时候可以写上

    go 复制代码
    func (l *GetTestLogic) GetTest() (resp *types.Response, err error) {
    	return &types.Response{
    		Code: "0",
    		Msg:  "成功",
    		Data: "hello world",
    	}, nil
    }
  • 3、参考官网地址

方式三、自定义模版,直接修改返回的数据方法(可以接受)
  • 1、定义方法

    go 复制代码
    package utils
    
    import (
    	"encoding/json"
    	"encoding/xml"
    	"errors"
    	"github.com/zeromicro/go-zero/core/logx"
    	"github.com/zeromicro/go-zero/rest/httpx"
    	"net/http"
    )
    
    type Body struct {
    	Code    int         `json:"code"`
    	Message string      `json:"message"`
    	Result  interface{} `json:"result"` // omitempty json里面加了这个表示如果为空的时候字段不返回
    }
    
    type PageVo struct {
    	Data       interface{} `json:"data"`       // 数据
    	Total      int64       `json:"total"`      // 总条数
    	PageSize   int64       `json:"pageSize"`   // 当前条数
    	PageNumber int64       `json:"pageNumber"` // 当前页数
    }
    
    // Response 一般返回
    func Response(w http.ResponseWriter, resp interface{}, err error) {
    	if err != nil {
    		httpx.OkJson(w, Body{
    			Code:    1,
    			Message: err.Error(),
    			Result:  nil,
    		})
    	} else {
    		httpx.OkJson(w, Body{
    			Code:    0,
    			Message: "请求成功",
    			Result:  resp,
    		})
    	}
    }
    
    // BuildPageData 返回分页数据
    func BuildPageData(w http.ResponseWriter, resp interface{}, total, pageSize, pageNumber int64, err error) {
    	if err != nil {
    		httpx.OkJson(w, Body{
    			Code:    1,
    			Message: err.Error(),
    			Result: PageVo{
    				Data:       nil,        // 数据
    				Total:      0,          // 总条数
    				PageSize:   pageSize,   // 当前条数
    				PageNumber: pageNumber, // 当前页数
    			},
    		})
    	} else {
    		httpx.OkJson(w, Body{
    			Code:    0,
    			Message: "请求成功",
    			Result: PageVo{
    				Data:       resp,       // 数据
    				Total:      total,      // 总条数
    				PageSize:   pageSize,   // 当前条数
    				PageNumber: pageNumber, // 当前页数
    			},
    		})
    	}
    }
    
    func WriteString(w http.ResponseWriter, code int, v string) {
    	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    	w.WriteHeader(code)
    	if n, err := w.Write([]byte(v)); err != nil {
    		// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
    		// so it's ignored here.
    		if !errors.Is(err, http.ErrHandlerTimeout) {
    			logx.Errorf("write response failed, error: %s", err)
    		}
    	} else if n < len(v) {
    		logx.Errorf("actual bytes: %d, written bytes: %d", len(v), n)
    	}
    }
    
    func WriteXml(w http.ResponseWriter, code int, v interface{}) {
    	bs, err := xml.Marshal(v)
    	if err != nil {
    		http.Error(w, err.Error(), http.StatusInternalServerError)
    		return
    	}
    
    	w.Header().Set("Content-Type", "text/xml")
    	w.Header().Set("response_body", string(bs))
    	w.WriteHeader(code)
    
    	if n, err := w.Write(bs); err != nil {
    		// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
    		// so it's ignored here.
    		if !errors.Is(err, http.ErrHandlerTimeout) {
    			logx.Errorf("write response failed, error: %s", err)
    		}
    	} else if n < len(bs) {
    		logx.Errorf("actual bytes: %d, written bytes: %d", len(bs), n)
    	}
    }
    
    func WriteFile(w http.ResponseWriter, fileBytes []byte, err error) {
    	var (
    		b []byte
    	)
    	if err != nil {
    		httpx.OkJson(w, err)
    		b, _ = json.Marshal(err)
    		w.Header().Set("response_body", string(b))
    		return
    	}
    
    	w.Header().Set("Content-Type", "application/octet-stream")
    	if n, err := w.Write(fileBytes); err != nil {
    		// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
    		// so it's ignored here.
    		if !errors.Is(err, http.ErrHandlerTimeout) {
    			logx.Errorf("write response failed, error: %s", err)
    		}
    	} else if n < len(fileBytes) {
    		logx.Errorf("actual bytes: %d, written bytes: %d", len(fileBytes), n)
    	}
    	w.WriteHeader(200)
    }
  • 2、定义模版handler.tpl

    properties 复制代码
    package {{.PkgName}}
    
    import (
    	"net/http"
    
    	"github.com/zeromicro/go-zero/rest/httpx"
    	{{.ImportPackages}}
    )
    
    func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
    	return func(w http.ResponseWriter, r *http.Request) {
    		{{if .HasRequest}}var req types.{{.RequestType}}
    		if err := httpx.Parse(r, &req); err != nil {
    			utils.TranslatorError(w, r, err)
    			return
    		}
    		
    		{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
    		{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
    		{{if .HasResp}}utils.Response(w, resp, err){{else}}utils.Response(w, nil, err){{end}}
    	}
    }
  • 3、使用自己的模版生成方法

    properties 复制代码
    goctl api go -api *api --dir . --style=goZero --home ../../goctl
  • 4、生成的代码中

    go 复制代码
    func DemoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    	return func(w http.ResponseWriter, r *http.Request) {
    		var req types.Request
    		if err := httpx.Parse(r, &req); err != nil {
    			httpx.ErrorCtx(r.Context(), w, err)
    			return
    		}
    		
    		l := demo.NewDemoLogic(r.Context(), svcCtx)
    		resp, err := l.Demo(&req)
    		utils.Response(w, resp, err)
    	}
    }
  • 5、这种方式不好的地方,在每个项目中导包可能不一样的,需要手动改动模版,或者把封装的方法封装成一个库发布

方式四、使用拦截器(最优方案)
  • 1、创建自己返回的方法

    go 复制代码
    package utils
    
    import (
    	"context"
    	"github.com/zeromicro/go-zero/core/logx"
    	"net/http"
    )
    
    type Response struct {
    	Code    int64       `json:"code"`
    	Message string      `json:"message"`
    	Result  interface{} `json:"result,omitempty"`
    }
    
    func Success(data interface{}) *Response {
    	return &Response{
    		Code:    0,
    		Message: "请求成功",
    		Result:  data,
    	}
    }
    
    func Fail(err string) *Response {
    	return &Response{
    		Code:    1,
    		Message: err,
    		Result:  nil,
    	}
    }
    
    func OkHandler(_ context.Context, v interface{}) any {
    	return Success(v)
    }
    
    func ErrHandler(name string) func(ctx context.Context, err error) (int, any) {
    	return func(ctx context.Context, err error) (int, any) {
    		// 日志记录
    		logx.WithContext(ctx).Errorf("【%s】 err %v", name, err)
    		return http.StatusBadRequest, Fail(err.Error())
    	}
    }
  • 2、在项目启动文件中添加自己的方法

go 复制代码
// 使用拦截器
httpx.SetOkHandler(utils.OkHandler)
httpx.SetErrorHandlerCtx(utils.ErrHandler(c.Name))
相关推荐
燃先生._.29 分钟前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
Dream_Snowar31 分钟前
速通Python 第三节
开发语言·python
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235241 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
信号处理学渣2 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客2 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
jasmine s2 小时前
Pandas
开发语言·python
biomooc2 小时前
R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)
开发语言·r语言
骇客野人2 小时前
【JAVA】JAVA接口公共返回体ResponseData封装
java·开发语言