go-自定义error

1 目标

自定义错误信息,以满足针对不同error进行不同的处理,或更多的错误信息输出。

2 原生error

  • 实现了以下func的任意类型,即可认为实现了error,且可使用errors包
type error interface {
    Error() string
}

3 errors包中Is\As比较的过程按以下顺序的三个条件进行判断,满足便退出:

  • 条件一:自定义类型无实现Is\As方法,直接进行比较。
  • 条件二:自定义类型实现Is\As方法,则调用err1.Is(err2)\err2.As(err2)。
  • 条件三:当前错误是否为errors.Join(…error)得到的错误,则会遍历错误链,递归调用errors.is(),重复判断过程;错误链之一满足条件即可退出。

4 故自定义函数需自行实现Is\As函数,用于自定义判断,完整函数代码如下:

package cerrors

import (
    "errors"
    "fmt"
    "time"
)

type CError struct {
    Code int
    Msg  string
    Time time.Time
    Type string
}

// 满足interface
func (e *CError) Error() string {
    s := fmt.Sprintf("type %s, msg %s, time %s", e.Type, e.Msg, e.Time.Format("2006-01-02 15:04:05"))
    return s
}

// errors.Is 默认最简情况:仅支持精确匹配 指针地址或值是否相等
// 自定义类型实现Is,可以进行更精细化的比较条件
func (e *CError) Is(target error) bool {
    var te *CError
    // 自定义错误类型比较
    if errors.As(target, &te) {
        return e.Code == te.Code && e.Type == te.Type
    }
    // 官方类型、其它类型直接返回错误
    return false
}

// errors.As 默认最简情况:仅支持类型完全匹配 二者的类型是否一致
// 自定义类型实现As,可以进行更精细化的类型转换
// target必须是双指针,即指针的指针
func (e *CError) As(target any) bool {
    // 判断target是否是指针的指针
    // 判断target是否能转成*CError,同种类型才能够从a转到target
    te, ok := target.(**CError)
    if !ok {
        return false
    }
    *te = e
    return true
}

const (
    CodeInfo    = 0
    CodeWarning = 1
    CodeError   = 2
)

const (
    TypeInfo    = "info"
    TypeWarning = "warning"
    TypeError   = "error"
)

func NewError(t string, msg string, code uint) *CError {
    return &CError{
        Msg:  msg,
        Type: t,
        Time: time.Now(),
    }
}

func Info(msg string) *CError {
    return NewError(TypeInfo, msg, CodeInfo)
}

func Warning(msg string) *CError {
    return NewError(TypeWarning, msg, CodeWarning)
}

func Error(msg string) *CError {
    return NewError(TypeError, msg, CodeError)
}
### go-zero 中自定义返回值的实现方法 `go-zero` 是一个云原生的 Go 微服务框架,提供了丰富的功能来简化微服务开发过程。在 `go-zero` 的 RPC 和 HTTP 接口中,可以通过修改接口逻辑来自定义返回值。 以下是关于如何在 `go-zero` 中实现自定义返回值的具体说明: #### 1. 定义 API 或 RPC 返回结构体 在 `go-zero` 的项目中,API 和 RPC 的返回值通常通过 Protobuf 文件或者 JSON Schema 来定义。如果需要自定义返回值,则可以在对应的 `.proto` 文件或 `api.yaml` 文件中重新设计返回数据结构。 对于 Protobuf 文件: ```protobuf syntax = "proto3"; package example; service ExampleService { rpc GetExample (GetRequest) returns (GetResponse); } message GetRequest { string id = 1; } message GetResponse { int32 code = 1; // 自定义状态码 string message = 2; // 自定义消息 Data data = 3; // 数据部分 } message Data { string name = 1; } ``` 上述代码展示了如何定义一个带有自定义字段(如 `code`, `message`)的响应结构[^2]。 #### 2. 修改业务逻辑以填充自定义返回值 在生成的服务文件中,可以调整具体的处理逻辑,在返回前设置所需的自定义字段。 以下是一个简单的示例代码片段: ```go func (l *Logic) GetExample(in *example.GetRequest) (*example.GetResponse, error) { var resp = &example.GetResponse{ Code: 0, Message: "Success", } if in.Id == "" { return &example.GetResponse{ Code: 400, Message: "Invalid input", }, nil } // 假设这里有一些复杂的业务逻辑 resp.Data = &example.Data{Name: "Test"} return resp, nil } ``` 在此示例中,`Code` 和 `Message` 字段被用于表示操作的状态和描述信息。这种模式允许客户端更灵活地解析错误情况并采取相应措施[^3]。 #### 3. 使用中间件统一管理返回值格式 为了减少重复代码量以及保持一致性,推荐使用 `go-zero` 提供的中间件功能对全局范围内的返回值进行封装。例如,创建一个通用的错误处理器作为中间件应用到所有路由上。 示例配置如下所示: ```yaml http: middleware: - customresponsemiddleware.CustomResponseMiddleware ``` 接着编写该中间件的内容: ```go import ( "net/http" "github.com/zeromicro/go-zero/rest/middleware" ) type CustomResponseMiddleware struct{} func NewCustomResponseMiddleware() middleware.Middleware { return func(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { resp := make(map[string]interface{}) defer func() { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) }() next.ServeHTTP(w, r) if errResp, ok := w.(interface{ Error() string }); ok && errResp.Error() != "" { resp["code"] = 500 resp["message"] = errResp.Error() return } resp["code"] = 200 resp["message"] = "OK" } } } ``` 此方法能够确保无论何种情况下都遵循相同的输出标准。 --- ### 总结 以上介绍了三种不同的方式来实现在 `go-zero` 框架下的自定义返回值:一是直接更改协议定义;二是针对特定场景单独定制化构建回复对象;三是利用插件形式集中管控整个系统的反馈样式。开发者可以根据实际需求选取最合适的方案实施。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值