This commit is contained in:
新亮
2021-02-19 22:00:01 +08:00
parent 334bfbb4aa
commit cc8012b09d
17 changed files with 521 additions and 194 deletions
+32 -19
View File
@@ -1,28 +1,41 @@
package code
import (
"net/http"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
var (
// OK
OK = errno.NewError(http.StatusOK, 1, "OK")
// 错误时返回结构
type Failure struct {
Code int `json:"code"` // 业务码
Message string `json:"message"` // 描述信息
}
const (
// 服务级错误码
ErrServer = errno.NewError(http.StatusInternalServerError, 10101, http.StatusText(http.StatusInternalServerError))
ErrManyRequest = errno.NewError(http.StatusTooManyRequests, 10102, http.StatusText(http.StatusTooManyRequests))
ErrParamBind = errno.NewError(http.StatusBadRequest, 10103, "参数信息有误")
ErrAuthorization = errno.NewError(http.StatusUnauthorized, 10104, "签名信息有误")
ServerError = 10101
TooManyRequests = 10102
ParamBindError = 10103
AuthorizationError = 10104
CallHTTPError = 10105
// 模块级错误码 - 用户模块
ErrUser = errno.NewError(http.StatusBadRequest, 20101, "非法用户")
ErrUserName = errno.NewError(http.StatusBadRequest, 20102, "账号不能为空")
ErrUserCreate = errno.NewError(http.StatusBadRequest, 20103, "创建用户失败")
ErrUserUpdate = errno.NewError(http.StatusBadRequest, 20104, "更新用户失败")
ErrUserSearch = errno.NewError(http.StatusBadRequest, 20105, "查询用户失败")
ErrUserHTTP = errno.NewError(http.StatusBadRequest, 20106, "调用他方接口失败")
IllegalUserName = 20101
UserCreateError = 20102
UserUpdateError = 20103
UserSearchError = 20104
// ...
)
var codeText = map[int]string{
ServerError: "Internal Server Error",
TooManyRequests: "Too Many Requests",
ParamBindError: "参数信息有误",
AuthorizationError: "签名信息有误",
CallHTTPError: "调用第三方 HTTP 接口失败",
IllegalUserName: "非法用户名",
UserCreateError: "创建用户失败",
UserUpdateError: "更新用户失败",
UserSearchError: "查询用户失败",
}
func Text(code int) string {
return codeText[code]
}
+55 -22
View File
@@ -1,6 +1,7 @@
package demo
import (
"net/http"
"time"
"github.com/xinliangnote/go-gin-api/configs"
@@ -11,6 +12,7 @@ import (
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/internal/pkg/grpc"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
"github.com/xinliangnote/go-gin-api/pkg/p"
"github.com/xinliangnote/go-gin-api/pkg/token"
@@ -49,19 +51,27 @@ func (d *Demo) Get() core.HandlerFunc {
return func(c core.Context) {
req := new(request)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(code.ErrParamBind.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
if req.Name != "Tom" {
c.AbortWithError(code.ErrUser.WithErr(errors.New("req.Name != Tom")))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.IllegalUserName,
code.Text(code.IllegalUserName)).WithErr(errors.New("req.Name != Tom")),
)
return
}
c.Payload(code.OK.WithData(&response{
c.Payload(&response{
Name: "Tom",
Job: "Student",
}))
})
}
}
@@ -78,19 +88,27 @@ func (d *Demo) Post() core.HandlerFunc {
return func(c core.Context) {
req := new(request)
if err := c.ShouldBindPostForm(req); err != nil {
c.AbortWithError(code.ErrParamBind.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
if req.Name != "Jack" {
c.AbortWithError(code.ErrUser.WithErr(errors.New("req.Name != Jack")))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.IllegalUserName,
code.Text(code.IllegalUserName)).WithErr(errors.New("req.Name != Jack")),
)
return
}
c.Payload(code.OK.WithData(&response{
c.Payload(&response{
Name: "Jack",
Job: "Teacher",
}))
})
}
}
@@ -110,14 +128,19 @@ type traceResponse []struct {
// @Tags Demo
// @Accept json
// @Produce json
// @Success 200 {object} authResponse "返回信息"
// @Success 200 {object} authResponse
// @Failure 400 {object} code.Failure
// @Router /auth/get [post]
func (d *Demo) Auth() core.HandlerFunc {
return func(c core.Context) {
cfg := configs.Get().JWT
tokenString, err := token.New(cfg.Secret).Sign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
if err != nil {
c.AbortWithError(code.ErrAuthorization.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizationError,
code.Text(code.AuthorizationError)).WithErr(err),
)
return
}
@@ -125,7 +148,7 @@ func (d *Demo) Auth() core.HandlerFunc {
res.Authorization = tokenString
res.ExpireTime = time.Now().Add(time.Hour * cfg.ExpireDuration).Unix()
c.Payload(code.OK.WithData(res))
c.Payload(res)
}
}
@@ -136,7 +159,9 @@ func (d *Demo) Auth() core.HandlerFunc {
// @Accept json
// @Produce json
// @Param Authorization header string true "签名"
// @Success 200 {object} traceResponse "用户信息"
// @Success 200 {object} traceResponse
// @Failure 400 {object} code.Failure
// @Failure 401 {object} code.Failure
// @Router /demo/trace [get]
func (d *Demo) Trace() core.HandlerFunc {
return func(c core.Context) {
@@ -151,12 +176,16 @@ func (d *Demo) Trace() core.HandlerFunc {
if err != nil {
d.logger.Error("get [demo/get] err", zap.Error(err))
c.AbortWithError(code.ErrUserHTTP.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.CallHTTPError,
code.Text(code.CallHTTPError)).WithErr(err),
)
return
}
// 调试信息
p.Println("res1.Data.Name", res1.Data.Name, p.WithTrace(c.Trace()))
p.Println("res1.Name", res1.Name, p.WithTrace(c.Trace()))
// 三方请求信息
res2, err := go_gin_api_repo.DemoPost("Jack",
@@ -169,13 +198,17 @@ func (d *Demo) Trace() core.HandlerFunc {
if err != nil {
d.logger.Error("post [demo/post] err", zap.Error(err))
c.AbortWithError(code.ErrUserHTTP.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.CallHTTPError,
code.Text(code.CallHTTPError)).WithErr(err),
)
return
}
// 调试信息
p.Println("res2.Data.Name",
res2.Data.Name,
p.Println("res2.Name",
res2.Name,
p.WithTrace(c.Trace()),
)
@@ -193,14 +226,14 @@ func (d *Demo) Trace() core.HandlerFunc {
data := &traceResponse{
{
Name: res1.Data.Name,
Job: res1.Data.Job,
Name: res1.Name,
Job: res1.Job,
},
{
Name: res2.Data.Name,
Job: res2.Data.Job,
Name: res2.Name,
Job: res2.Job,
},
}
c.Payload(code.OK.WithData(data))
c.Payload(data)
}
}
+66 -17
View File
@@ -2,6 +2,7 @@ package user_handler
import (
"errors"
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/api/model/user_model"
@@ -10,6 +11,7 @@ import (
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/pkg/ddm"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"go.uber.org/zap"
)
@@ -57,30 +59,45 @@ func (u *userDemo) i() {}
// @Produce json
// @Param RequestInfo body user_model.CreateRequest true "请求信息"
// @Param Authorization header string true "签名"
// @Success 200 {object} user_model.CreateResponse "返回信息"
// @Success 200 {object} user_model.CreateResponse
// @Failure 400 {object} code.Failure
// @Failure 401 {object} code.Failure
// @Router /user/create [post]
func (u *userDemo) Create() core.HandlerFunc {
return func(c core.Context) {
req := new(user_model.CreateRequest)
res := new(user_model.CreateResponse)
if err := c.ShouldBindJSON(req); err != nil {
c.AbortWithError(code.ErrParamBind.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
if req.UserName == "" {
c.AbortWithError(code.ErrUserName.WithErr(errors.New("req.UserName = ''")))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.IllegalUserName,
code.Text(code.IllegalUserName)).WithErr(errors.New("req.UserName = ''")),
)
return
}
id, err := u.userService.Create(c, req)
if err != nil {
c.AbortWithError(code.ErrUserCreate.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.UserCreateError,
code.Text(code.UserCreateError)).WithErr(err),
)
return
}
res.Id = id
c.Payload(code.OK.WithData(res))
c.Payload(res)
}
}
@@ -92,25 +109,36 @@ func (u *userDemo) Create() core.HandlerFunc {
// @Produce json
// @Param RequestInfo body user_model.UpdateNickNameByIDRequest true "请求信息"
// @Param Authorization header string true "签名"
// @Success 200 {object} user_model.UpdateNickNameByIDResponse "返回信息"
// @Success 200 {object} user_model.UpdateNickNameByIDResponse
// @Failure 400 {object} code.Failure
// @Failure 401 {object} code.Failure
// @Router /user/update [put]
func (u *userDemo) UpdateNickNameByID() core.HandlerFunc {
return func(c core.Context) {
req := new(user_model.UpdateNickNameByIDRequest)
res := new(user_model.UpdateNickNameByIDResponse)
if err := c.ShouldBindJSON(req); err != nil {
c.AbortWithError(code.ErrParamBind.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
err := u.userService.UpdateNickNameByID(c, req.Id, req.NickName)
if err != nil {
c.AbortWithError(code.ErrUserUpdate.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.UserUpdateError,
code.Text(code.UserUpdateError)).WithErr(err),
)
return
}
res.Id = req.Id
c.Payload(code.OK.WithData(res))
c.Payload(res)
}
}
@@ -122,23 +150,33 @@ func (u *userDemo) UpdateNickNameByID() core.HandlerFunc {
// @Produce json
// @Param id path int true "用户ID"
// @Param Authorization header string true "签名"
// @Success 200 "返回信息"
// @Success 200
// @Failure 400 {object} code.Failure
// @Failure 401 {object} code.Failure
// @Router /user/delete/{id} [patch]
func (u *userDemo) Delete() core.HandlerFunc {
return func(c core.Context) {
req := new(user_model.DeleteRequest)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(code.ErrParamBind.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
err := u.userService.Delete(c, req.Id)
if err != nil {
c.AbortWithError(code.ErrUserUpdate.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.UserUpdateError,
code.Text(code.UserUpdateError)).WithErr(err),
)
return
}
c.Payload(code.OK.WithData(nil))
c.Payload("")
}
}
@@ -150,20 +188,30 @@ func (u *userDemo) Delete() core.HandlerFunc {
// @Produce json
// @Param username path string true "用户名"
// @Param Authorization header string true "签名"
// @Success 200 {object} user_model.DetailResponse "返回信息"
// @Success 200 {object} user_model.DetailResponse
// @Failure 400 {object} code.Failure
// @Failure 401 {object} code.Failure
// @Router /user/info/{username} [get]
func (u *userDemo) Detail() core.HandlerFunc {
return func(c core.Context) {
req := new(user_model.DetailRequest)
res := new(user_model.DetailResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(code.ErrParamBind.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
user, err := u.userService.GetUserByUserName(c, req.UserName)
if err != nil {
c.AbortWithError(code.ErrUserSearch.WithErr(err))
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.UserSearchError,
code.Text(code.UserSearchError)).WithErr(err),
)
return
}
@@ -171,6 +219,7 @@ func (u *userDemo) Detail() core.HandlerFunc {
res.UserName = user.UserName
res.NickName = user.NickName
res.Mobile = ddm.Mobile(user.Mobile)
c.Payload(code.OK.WithData(res))
c.Payload(res)
}
}
@@ -2,7 +2,6 @@ package go_gin_api_repo
import (
"encoding/json"
"fmt"
"net/url"
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
@@ -11,23 +10,13 @@ import (
)
type demoGetResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Name string `json:"name"`
Job string `json:"job"`
} `json:"data"`
ID string `json:"id"`
Name string `json:"name"`
Job string `json:"job"`
}
type demoPostResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Name string `json:"name"`
Job string `json:"job"`
} `json:"data"`
ID string `json:"id"`
Name string `json:"name"`
Job string `json:"job"`
}
func DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err error) {
@@ -43,10 +32,6 @@ func DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err
return nil, errors.Wrap(err, "DemoGet json unmarshal error")
}
if res.Code != 1 {
return nil, errors.New(fmt.Sprintf("code err: %d-%s", res.Code, res.Msg))
}
return res, nil
}
@@ -55,17 +40,7 @@ func DemoGetRetryVerify(body []byte) (shouldRetry bool) {
return true
}
type Response struct {
Code int `json:"code"`
}
resp := new(Response)
if err := json.Unmarshal(body, resp); err != nil {
return true
}
// 例如 无需重试的 code 码,code !=1 需要重试
successCode := 1
return resp.Code != successCode
return false
}
func DemoPost(name string, opts ...httpclient.Option) (res *demoPostResponse, err error) {
@@ -83,10 +58,6 @@ func DemoPost(name string, opts ...httpclient.Option) (res *demoPostResponse, er
return nil, errors.Wrap(err, "DemoPost json unmarshal error")
}
if res.Code != 1 {
return nil, errors.New(fmt.Sprintf("code err: %d-%s", res.Code, res.Msg))
}
return res, nil
}
@@ -95,15 +66,5 @@ func DemoPostRetryVerify(body []byte) (shouldRetry bool) {
return true
}
type Response struct {
Code int `json:"code"`
}
resp := new(Response)
if err := json.Unmarshal(body, resp); err != nil {
return true
}
// 例如 无需重试的 code 码,code !=1 需要重试
successCode := 1
return resp.Code != successCode
return false
}
@@ -4,10 +4,8 @@ import "encoding/json"
func MockDemoGet() (body []byte) {
res := new(demoGetResponse)
res.Code = 1
res.Msg = "ok"
res.Data.Name = "AA"
res.Data.Job = "AA_JOB"
res.Name = "AA"
res.Job = "AA_JOB"
body, _ = json.Marshal(res)
return body
@@ -15,10 +13,8 @@ func MockDemoGet() (body []byte) {
func MockDemoPost() (body []byte) {
res := new(demoPostResponse)
res.Code = 1
res.Msg = "ok"
res.Data.Name = "BB"
res.Data.Job = "BB_JOB"
res.Name = "BB"
res.Job = "BB_JOB"
body, _ = json.Marshal(res)
return body
@@ -9,7 +9,7 @@ import (
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
)
var authorization = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEwLCJVc2VyTmFtZSI6IjEyMyIsImV4cCI6MTYxMDcxODA3NCwiaWF0IjoxNjEwNjMxNjc0LCJpc3MiOiJnby1naW4tYXBpIiwibmJmIjoxNjEwNjMxNjc0fQ.S3T4MaIaz3XjkbJ-xkMDkwzuZ_jfZ8ZRf4cPMz0oXBE"
var authorization = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEsIlVzZXJOYW1lIjoieGlubGlhbmdub3RlIiwiZXhwIjoxNjEzODI3MTEzLCJpYXQiOjE2MTM3NDA3MTMsIm5iZiI6MTYxMzc0MDcxM30.SnooP1ikO33ryGPdohsmOKqISa-bWzMkMvUNb5f2zc0"
func TestDemoGet(t *testing.T) {
res, err := DemoGet("Tom",
+17 -3
View File
@@ -1,6 +1,8 @@
package auth
import (
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
@@ -13,20 +15,32 @@ import (
func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Error) {
auth := ctx.GetHeader("Authorization")
if auth == "" {
err = code.ErrAuthorization.WithErr(errors.New("Header 中缺少 Authorization 参数"))
err = errno.NewError(
http.StatusUnauthorized,
code.AuthorizationError,
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Authorization 参数"))
return
}
cfg := configs.Get().JWT
claims, errParse := token.New(cfg.Secret).Parse(auth)
if errParse != nil {
err = code.ErrAuthorization.WithErr(errParse)
err = errno.NewError(
http.StatusUnauthorized,
code.AuthorizationError,
code.Text(code.AuthorizationError)).WithErr(errParse)
return
}
userId = claims.UserID
if userId <= 0 {
err = code.ErrAuthorization.WithErr(errors.New("claims.UserID <= 0 "))
err = errno.NewError(
http.StatusUnauthorized,
code.AuthorizationError,
code.Text(code.AuthorizationError)).WithErr(errors.New("claims.UserID <= 0 "))
return
}
userName = claims.UserName
+5 -5
View File
@@ -90,8 +90,8 @@ type Context interface {
setLogger(logger *zap.Logger)
// Payload 正确返回
Payload(payload errno.Error)
getPayload() errno.Error
Payload(payload interface{})
getPayload() interface{}
// GraphPayload GraphQL返回值 与 api 返回结构不同
GraphPayload(payload interface{})
@@ -225,14 +225,14 @@ func (c *context) setLogger(logger *zap.Logger) {
c.ctx.Set(_LoggerName, logger)
}
func (c *context) getPayload() errno.Error {
func (c *context) getPayload() interface{} {
if payload, ok := c.ctx.Get(_PayloadName); ok != false {
return payload.(errno.Error)
return payload
}
return nil
}
func (c *context) Payload(payload errno.Error) {
func (c *context) Payload(payload interface{}) {
c.ctx.Set(_PayloadName, payload)
}
+23 -11
View File
@@ -336,7 +336,11 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
if err := recover(); err != nil {
stackInfo := string(debug.Stack())
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
context.AbortWithError(code.ErrServer)
context.AbortWithError(errno.NewError(
http.StatusInternalServerError,
code.ServerError,
code.Text(code.ServerError)),
)
if notify := opt.panicNotify; notify != nil {
notify(context, err, stackInfo)
@@ -348,7 +352,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
}
var (
response errno.Error
response interface{}
businessCode int
businessCodeMsg string
abortErr error
@@ -364,23 +368,27 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
if err := context.abortError(); err != nil { // customer err
multierr.AppendInto(&abortErr, err.GetErr())
response = err
businessCode = err.GetBusinessCode()
businessCodeMsg = err.GetMsg()
reply := &code.Failure{
Code: businessCode,
Message: businessCodeMsg,
}
ctx.JSON(err.GetHttpCode(), reply)
}
} else {
response = context.getPayload()
if response != nil {
ctx.JSON(http.StatusOK, response)
}
}
if response != nil {
if x := context.Trace(); x != nil {
context.SetHeader(trace.Header, x.ID())
response.WithID(x.ID())
traceId = x.ID()
} else {
response.WithID("")
}
businessCode = response.GetBusinessCode()
businessCodeMsg = response.GetMsg()
ctx.JSON(response.GetHttpCode(), response)
}
graphResponse = context.getGraphPayload()
@@ -464,7 +472,11 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
defer releaseContext(context)
if !limiter.Allow() {
context.AbortWithError(code.ErrManyRequest)
context.AbortWithError(errno.NewError(
http.StatusTooManyRequests,
code.TooManyRequests,
code.Text(code.TooManyRequests)),
)
return
}
@@ -489,7 +501,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
Host: ctx.Host(),
Status: "ok",
}
ctx.Payload(code.OK.WithData(resp))
ctx.Payload(resp)
})
}
+12 -2
View File
@@ -3,12 +3,14 @@ package grpc
import (
"context"
"fmt"
"net/http"
"runtime/debug"
"time"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/p"
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
"github.com/xinliangnote/go-gin-api/pkg/trace"
@@ -53,7 +55,11 @@ func (c *ClientInterceptor) UnaryInterceptor(ctx context.Context, method string,
if err := recover(); err != nil {
stackInfo := string(debug.Stack())
coreContext.Logger().Error("UnaryInterceptor got double panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
coreContext.AbortWithError(code.ErrServer)
coreContext.AbortWithError(errno.NewError(
http.StatusInternalServerError,
code.ServerError,
code.Text(code.ServerError)),
)
notify.OnPanicNotify(coreContext, err, stackInfo)
}
}()
@@ -62,7 +68,11 @@ func (c *ClientInterceptor) UnaryInterceptor(ctx context.Context, method string,
if err := recover(); err != nil {
stackInfo := string(debug.Stack())
coreContext.Logger().Error("UnaryInterceptor got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
coreContext.AbortWithError(code.ErrServer)
coreContext.AbortWithError(errno.NewError(
http.StatusInternalServerError,
code.ServerError,
code.Text(code.ServerError)),
)
notify.OnPanicNotify(coreContext, err, stackInfo)
}