介绍
本文通过一个完整的例子,介绍通过 rk-boot 实现标准化的后台服务错误码。
我们将会使用 rk-boot/v2 来启动 gin-gonic/gin 后台微服务进行展示。
默认使用 Google 样式的错误。 - Google 样式
{
"error":{
"code":500,
"status":"Internal Server Error",
"message":"Panic occurs",
"details":[
"panic manually"
]
}
}- Amazon 样式
{
"response":{
"errors":[
{
"error":{
"code":500,
"status":"Internal Server Error",
"message":"Panic occurs",
"details":[
"panic manually"
]
}
}
]
}
}- 自定义样式请参照后面的例子。
其他微服务文档请参考如下链接:
| Web 框架 | 官方文档 |
|---|---|
| gin-gonic/gin | 官方文档 |
| gRPC | 官方文档 |
| labstack/echo | 官方文档 |
| gogf/gf | 官方文档 |
| gofiber/fiber | 官方文档 |
| zeromicro/go-zero | 官方文档 |
| gorilla/mux | 官方文档 |
安装
$ go get github.com/rookie-ninja/rk-boot/v2
$ go get github.com/rookie-ninja/rk-gin/v2
快速开始
1.创建 boot.yaml
boot.yaml 文件描述了 Gin 框架启动的元信息,rk-boot 通过读取 boot.yaml 来启动 Gin。
---
gin:
- name: greeter
port: 8080
enabled: true2.创建 main.go
让 /v1/greeter 返回一个错误。
package main
import (
"context"
"github.com/gin-gonic/gin"
"github.com/rookie-ninja/rk-boot/v2"
"github.com/rookie-ninja/rk-entry/v2/error"
"github.com/rookie-ninja/rk-gin/v2/boot"
"net/http"
)
func main() {
// Create a new boot instance.
boot := rkboot.NewBoot()
// Register handler
entry := rkgin.GetGinEntry("greeter")
entry.Router.GET("/v1/greeter", Greeter)
// Bootstrap
boot.Bootstrap(context.TODO())
boot.WaitForShutdownSig(context.TODO())
}
func Greeter(ctx *gin.Context) {
err := rkmid.GetErrorBuilder().New(http.StatusAlreadyReported, "Trigger manually!",
"This is detail.",
false, -1,
0.1)
ctx.JSON(http.StatusAlreadyReported, err)
}
3.验证
$ curl "localhost:8080/v1/greeter?name=rk-dev"
{
"error":{
"code":208,
"status":"Already Reported",
"message":"Trigger manually!",
"details":[
"This is detail.",
false,
-1,
0.1
]
}
}Amazon 样式错误
需要在 boot.yaml 中定义错误模型为 amazon。
- boot.yaml
gin:
- name: greeter
port: 8080
enabled: true
middleware:
errorModel: amazon
{
"response":{
"errors":[
{
"error":{
"code":208,
"status":"Already Reported",
"message":"Trigger manually!",
"details":[
"This is detail.",
false,
-1,
0.1
]
}
}
]
}
}自定义样式
实现如下两个接口,并注册到 Entry 中。
type ErrorInterface interface {
Error() string
Code() int
Message() string
Details() []interface{}
}
type ErrorBuilder interface {
New(code int, msg string, details ...interface{}) ErrorInterface
NewCustom() ErrorInterface
}
main.go
package main
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/rookie-ninja/rk-boot/v2"
"github.com/rookie-ninja/rk-entry/v2/error"
"github.com/rookie-ninja/rk-entry/v2/middleware"
"github.com/rookie-ninja/rk-gin/v2/boot"
"net/http"
)
func main() {
// Create a new boot instance.
boot := rkboot.NewBoot()
// Register handler
entry := rkgin.GetGinEntry("greeter")
entry.Router.GET("/v1/greeter", Greeter)
// Bootstrap
boot.Bootstrap(context.TODO())
// Set default error builder after bootstrap
rkmid.SetErrorBuilder(&MyErrorBuilder{})
boot.WaitForShutdownSig(context.TODO())
}
func Greeter(ctx *gin.Context) {
err := rkmid.GetErrorBuilder().New(http.StatusAlreadyReported, "Trigger manually!",
"This is detail.",
false, -1,
0.1)
ctx.JSON(http.StatusAlreadyReported, err)
}
type MyError struct {
ErrCode int
ErrMsg string
ErrDetails []interface{}
}
func (m MyError) Error() string {
return fmt.Sprintf("%d-%s", m.ErrCode, m.ErrMsg)
}
func (m MyError) Code() int {
return m.ErrCode
}
func (m MyError) Message() string {
return m.ErrMsg
}
func (m MyError) Details() []interface{} {
return m.ErrDetails
}
type MyErrorBuilder struct{}
func (m *MyErrorBuilder) New(code int, msg string, details ...interface{}) rkerror.ErrorInterface {
return &MyError{
ErrCode: code,
ErrMsg: msg,
ErrDetails: details,
}
}
func (m *MyErrorBuilder) NewCustom() rkerror.ErrorInterface {
return &MyError{
ErrCode: http.StatusInternalServerError,
ErrMsg: "Internal Error",
ErrDetails: []interface{}{},
}
}
验证
$ curl "localhost:8080/v1/greeter?name=rk-dev"
{
"ErrCode":208,
"ErrMsg":"Trigger manually!",
"ErrDetails":[
"This is detail.",
false,
-1,
0.1
]
}原理
当通过 rk-boot 启动微服务的时候,rk-boot 默认会基于 boot.yaml 里的配置,创建一个 ErrorBuilder 实例。 用户只要通过 rkmid.GetErrorBuilder().New() 方法创建错误即可。
rk-boot 默认的 panic handler 中间件也会使用 ErrorBuilder 返回统一格式的错误,保证整个服务的错误码一致。