From cc8012b09d8c9286b4418dff7a538b1b00b32a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B0=E4=BA=AE?= Date: Fri, 19 Feb 2021 22:00:01 +0800 Subject: [PATCH] upgrade --- docs/docs.go | 93 +++++++++++++++++-- docs/swagger.json | 93 +++++++++++++++++-- docs/swagger.yaml | 67 +++++++++++-- internal/api/code/code.go | 51 ++++++---- internal/api/controller/demo/demo.go | 77 ++++++++++----- internal/api/controller/user_handler/user.go | 83 +++++++++++++---- .../go_gin_api_repo/go_gin_api.go | 51 ++-------- .../go_gin_api_repo/go_gin_api_mock.go | 12 +-- .../go_gin_api_repo/go_gin_api_test.go | 2 +- internal/api/router/middleware/auth/auth.go | 20 +++- internal/pkg/core/context.go | 10 +- internal/pkg/core/core.go | 34 ++++--- internal/pkg/grpc/interceptor.go | 14 ++- main.go | 14 +-- pkg/errno/errno.go | 42 ++------- pkg/httpclient/error.go | 46 +++++++++ pkg/httpclient/util.go | 6 +- 17 files changed, 521 insertions(+), 194 deletions(-) create mode 100644 pkg/httpclient/error.go diff --git a/docs/docs.go b/docs/docs.go index a02b214..958b626 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -43,10 +43,16 @@ var doc = `{ "summary": "获取授权信息", "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/demo.authResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -75,7 +81,7 @@ var doc = `{ ], "responses": { "200": { - "description": "用户信息", + "description": "OK", "schema": { "type": "array", "items": { @@ -92,6 +98,18 @@ var doc = `{ } } } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -129,10 +147,22 @@ var doc = `{ ], "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/user_model.CreateResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -168,7 +198,19 @@ var doc = `{ ], "responses": { "200": { - "description": "返回信息" + "description": "" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -204,10 +246,22 @@ var doc = `{ ], "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/user_model.DetailResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -245,16 +299,41 @@ var doc = `{ ], "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/user_model.UpdateNickNameByIDResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } } }, "definitions": { + "code.Failure": { + "type": "object", + "properties": { + "code": { + "description": "业务码", + "type": "integer" + }, + "message": { + "description": "描述信息", + "type": "string" + } + } + }, "demo.authResponse": { "type": "object", "properties": { @@ -302,7 +381,7 @@ var doc = `{ "type": "integer" }, "mobile": { - "description": "手机号", + "description": "手机号(脱敏)", "type": "string" }, "nick_name": { diff --git a/docs/swagger.json b/docs/swagger.json index 2d88d30..1eb20a1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -26,10 +26,16 @@ "summary": "获取授权信息", "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/demo.authResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -58,7 +64,7 @@ ], "responses": { "200": { - "description": "用户信息", + "description": "OK", "schema": { "type": "array", "items": { @@ -75,6 +81,18 @@ } } } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -112,10 +130,22 @@ ], "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/user_model.CreateResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -151,7 +181,19 @@ ], "responses": { "200": { - "description": "返回信息" + "description": "" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -187,10 +229,22 @@ ], "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/user_model.DetailResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } @@ -228,16 +282,41 @@ ], "responses": { "200": { - "description": "返回信息", + "description": "OK", "schema": { "$ref": "#/definitions/user_model.UpdateNickNameByIDResponse" } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/code.Failure" + } } } } } }, "definitions": { + "code.Failure": { + "type": "object", + "properties": { + "code": { + "description": "业务码", + "type": "integer" + }, + "message": { + "description": "描述信息", + "type": "string" + } + } + }, "demo.authResponse": { "type": "object", "properties": { @@ -285,7 +364,7 @@ "type": "integer" }, "mobile": { - "description": "手机号", + "description": "手机号(脱敏)", "type": "string" }, "nick_name": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 703f4c6..639b02f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,13 @@ definitions: + code.Failure: + properties: + code: + description: 业务码 + type: integer + message: + description: 描述信息 + type: string + type: object demo.authResponse: properties: authorization: @@ -32,7 +41,7 @@ definitions: description: 用户主键ID type: integer mobile: - description: 手机号 + description: 手机号(脱敏) type: string nick_name: description: 昵称 @@ -74,9 +83,13 @@ paths: - application/json responses: "200": - description: 返回信息 + description: OK schema: $ref: '#/definitions/demo.authResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' summary: 获取授权信息 tags: - Demo @@ -95,7 +108,7 @@ paths: - application/json responses: "200": - description: 用户信息 + description: OK schema: items: properties: @@ -107,6 +120,14 @@ paths: type: string type: object type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/code.Failure' summary: Trace 示例 tags: - Demo @@ -131,9 +152,17 @@ paths: - application/json responses: "200": - description: 返回信息 + description: OK schema: $ref: '#/definitions/user_model.CreateResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/code.Failure' summary: 创建用户 tags: - User @@ -157,7 +186,15 @@ paths: - application/json responses: "200": - description: 返回信息 + description: "" + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/code.Failure' summary: 删除用户 - 更新 is_deleted = 1 tags: - User @@ -181,9 +218,17 @@ paths: - application/json responses: "200": - description: 返回信息 + description: OK schema: $ref: '#/definitions/user_model.DetailResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/code.Failure' summary: 用户详情 tags: - User @@ -208,9 +253,17 @@ paths: - application/json responses: "200": - description: 返回信息 + description: OK schema: $ref: '#/definitions/user_model.UpdateNickNameByIDResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/code.Failure' summary: 编辑用户 - 通过用户主键ID更新用户昵称 tags: - User diff --git a/internal/api/code/code.go b/internal/api/code/code.go index b69a82b..797d7b6 100644 --- a/internal/api/code/code.go +++ b/internal/api/code/code.go @@ -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] +} diff --git a/internal/api/controller/demo/demo.go b/internal/api/controller/demo/demo.go index ed7e771..4625191 100644 --- a/internal/api/controller/demo/demo.go +++ b/internal/api/controller/demo/demo.go @@ -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) } } diff --git a/internal/api/controller/user_handler/user.go b/internal/api/controller/user_handler/user.go index b958492..21fc63f 100644 --- a/internal/api/controller/user_handler/user.go +++ b/internal/api/controller/user_handler/user.go @@ -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) } } diff --git a/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api.go b/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api.go index d24848c..b348938 100644 --- a/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api.go +++ b/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api.go @@ -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 } diff --git a/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_mock.go b/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_mock.go index fdfa057..9b21c66 100644 --- a/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_mock.go +++ b/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_mock.go @@ -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 diff --git a/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_test.go b/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_test.go index 00ffe81..948227e 100644 --- a/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_test.go +++ b/internal/api/repository/third_party_request/go_gin_api_repo/go_gin_api_test.go @@ -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", diff --git a/internal/api/router/middleware/auth/auth.go b/internal/api/router/middleware/auth/auth.go index 38b3633..9ac01df 100644 --- a/internal/api/router/middleware/auth/auth.go +++ b/internal/api/router/middleware/auth/auth.go @@ -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 diff --git a/internal/pkg/core/context.go b/internal/pkg/core/context.go index 0c57efe..e331f75 100644 --- a/internal/pkg/core/context.go +++ b/internal/pkg/core/context.go @@ -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) } diff --git a/internal/pkg/core/core.go b/internal/pkg/core/core.go index 824be6b..7e750d6 100644 --- a/internal/pkg/core/core.go +++ b/internal/pkg/core/core.go @@ -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) }) } diff --git a/internal/pkg/grpc/interceptor.go b/internal/pkg/grpc/interceptor.go index fbe06c2..de6d735 100644 --- a/internal/pkg/grpc/interceptor.go +++ b/internal/pkg/grpc/interceptor.go @@ -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) } diff --git a/main.go b/main.go index cb54bb0..f2f1f15 100644 --- a/main.go +++ b/main.go @@ -117,12 +117,12 @@ func main() { }, // 关闭 gRPC client - func() { - if err := gRPCRepo.Conn().Close(); err != nil { - loggers.Error("gRPC client close err", zap.Error(err)) - } else { - loggers.Info("gRPC client close success") - } - }, + //func() { + // if err := gRPCRepo.Conn().Close(); err != nil { + // loggers.Error("gRPC client close err", zap.Error(err)) + // } else { + // loggers.Info("gRPC client close success") + // } + //}, ) } diff --git a/pkg/errno/errno.go b/pkg/errno/errno.go index c8d2241..0f237d6 100644 --- a/pkg/errno/errno.go +++ b/pkg/errno/errno.go @@ -11,10 +11,6 @@ var _ Error = (*err)(nil) type Error interface { // i 为了避免被其他包实现 i() - // WithData 设置成功时返回的数据 - WithData(data interface{}) Error - // WithID 设置当前请求的唯一ID - WithID(id string) Error // WithErr 设置错误信息 WithErr(err error) Error // GetBusinessCode 获取 Business Code @@ -30,36 +26,22 @@ type Error interface { } type err struct { - HttpCode int `json:"-"` // HTTP Code - BusinessCode int `json:"code"` // Business Code - Msg string `json:"msg"` // 描述信息 - Data interface{} `json:"data"` // 接口数据 - Err error `json:"-"` // 错误信息 - ID string `json:"id,omitempty"` // 当前请求的唯一ID,便于问题定位,忽略也可以 + HttpCode int // HTTP Code + BusinessCode int // Business Code + Message string // 描述信息 + Err error // 错误信息 } func NewError(httpCode, businessCode int, msg string) Error { return &err{ HttpCode: httpCode, BusinessCode: businessCode, - Msg: msg, - Data: nil, - Err: nil, + Message: msg, } } func (e *err) i() {} -func (e *err) WithData(data interface{}) Error { - e.Data = data - return e -} - -func (e *err) WithID(id string) Error { - e.ID = id - return e -} - func (e *err) WithErr(err error) Error { e.Err = errors.WithStack(err) return e @@ -74,7 +56,7 @@ func (e *err) GetBusinessCode() int { } func (e *err) GetMsg() string { - return e.Msg + return e.Message } func (e *err) GetErr() error { @@ -84,17 +66,13 @@ func (e *err) GetErr() error { // ToString 返回 JSON 格式的错误详情 func (e *err) ToString() string { err := &struct { - HttpCode int `json:"http_code"` - BusinessCode int `json:"business_code"` - Msg string `json:"msg"` - Data interface{} `json:"data"` - ID string `json:"id,omitempty"` + HttpCode int `json:"http_code"` + BusinessCode int `json:"business_code"` + Message string `json:"message"` }{ HttpCode: e.HttpCode, BusinessCode: e.BusinessCode, - Msg: e.Msg, - Data: e.Data, - ID: e.ID, + Message: e.Message, } raw, _ := json.Marshal(err) diff --git a/pkg/httpclient/error.go b/pkg/httpclient/error.go new file mode 100644 index 0000000..647f1fd --- /dev/null +++ b/pkg/httpclient/error.go @@ -0,0 +1,46 @@ +package httpclient + +var _ ReplyErr = (*replyErr)(nil) + +// ReplyErr 错误响应,当 resp.StatusCode != http.StatusOK 时用来包装返回的 httpcode 和 body 。 +type ReplyErr interface { + error + StatusCode() int + Body() []byte +} + +type replyErr struct { + err error + statusCode int + body []byte +} + +func (r *replyErr) Error() string { + return r.err.Error() +} + +func (r *replyErr) StatusCode() int { + return r.statusCode +} + +func (r *replyErr) Body() []byte { + return r.body +} + +func newReplyErr(statusCode int, body []byte, err error) ReplyErr { + return &replyErr{ + statusCode: statusCode, + body: body, + err: err, + } +} + +// ToReplyErr 尝试将 err 转换为 ReplyErr +func ToReplyErr(err error) (ReplyErr, bool) { + if err == nil { + return nil, false + } + + e, ok := err.(ReplyErr) + return e, ok +} diff --git a/pkg/httpclient/util.go b/pkg/httpclient/util.go index 068833f..9b7bdc1 100644 --- a/pkg/httpclient/util.go +++ b/pkg/httpclient/util.go @@ -105,7 +105,11 @@ func doHTTP(ctx context.Context, method, url string, payload []byte, opt *option }() if resp.StatusCode != http.StatusOK { - return body, resp.StatusCode, errors.Errorf("do [%s %s] return code: %d message: %s", method, url, resp.StatusCode, string(body)) + return nil, resp.StatusCode, newReplyErr( + resp.StatusCode, + body, + errors.Errorf("do [%s %s] return code: %d message: %s", method, url, resp.StatusCode, string(body)), + ) } return body, http.StatusOK, nil