Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
xuthus5 | e2f6f1ad3a | |
xuthus5 | 0469c4d45a | |
Young Xu | 14f42cfded |
38
core.pb.go
38
core.pb.go
|
@ -1,7 +1,7 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.5
|
||||
// protoc v5.26.1
|
||||
// source: core.proto
|
||||
|
||||
package coco
|
||||
|
@ -25,11 +25,12 @@ type ErrMsg struct {
|
|||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ErrCode int32 `protobuf:"varint,1,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"` // 错误码
|
||||
ErrMsg string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"` // 错误信息
|
||||
Hint string `protobuf:"bytes,3,opt,name=hint,proto3" json:"hint,omitempty"` // 日志ID
|
||||
ErrCode int32 `protobuf:"varint,1,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"` // 错误码
|
||||
ErrMsg string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"` // 错误信息
|
||||
Hint string `protobuf:"bytes,3,opt,name=hint,proto3" json:"hint,omitempty"` // 请求标记
|
||||
RequestId string `protobuf:"bytes,4,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` // 请求id
|
||||
// @json: -
|
||||
Autonomy bool `protobuf:"varint,4,opt,name=autonomy,proto3" json:"autonomy,omitempty"` //
|
||||
Autonomy bool `protobuf:"varint,5,opt,name=autonomy,proto3" json:"autonomy,omitempty"` // 框架自动化
|
||||
}
|
||||
|
||||
func (x *ErrMsg) Reset() {
|
||||
|
@ -85,6 +86,13 @@ func (x *ErrMsg) GetHint() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *ErrMsg) GetRequestId() string {
|
||||
if x != nil {
|
||||
return x.RequestId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ErrMsg) GetAutonomy() bool {
|
||||
if x != nil {
|
||||
return x.Autonomy
|
||||
|
@ -96,14 +104,16 @@ var File_core_proto protoreflect.FileDescriptor
|
|||
|
||||
var file_core_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x22, 0x6c, 0x0a, 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07,
|
||||
0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d,
|
||||
0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x68, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
|
||||
0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x3b, 0x63, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x63, 0x6f, 0x22, 0x8b, 0x01, 0x0a, 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x19, 0x0a,
|
||||
0x08, 0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f,
|
||||
0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73,
|
||||
0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x68, 0x69, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
|
||||
0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x3b, 0x63, 0x6f, 0x63, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
|
@ -121,7 +131,7 @@ func file_core_proto_rawDescGZIP() []byte {
|
|||
|
||||
var file_core_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_core_proto_goTypes = []interface{}{
|
||||
(*ErrMsg)(nil), // 0: core.ErrMsg
|
||||
(*ErrMsg)(nil), // 0: coco.ErrMsg
|
||||
}
|
||||
var file_core_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
|
|
10
core.proto
10
core.proto
|
@ -4,10 +4,12 @@ package coco;
|
|||
|
||||
option go_package = "./;coco";
|
||||
|
||||
|
||||
message ErrMsg {
|
||||
int32 err_code = 1; // 错误码
|
||||
string err_msg = 2; // 错误信息
|
||||
string hint = 3; // 日志ID
|
||||
int32 err_code = 1; // 错误码
|
||||
string err_msg = 2; // 错误信息
|
||||
string hint = 3; // 请求标记
|
||||
string request_id = 4; // 请求id
|
||||
// @json: -
|
||||
bool autonomy = 4; //
|
||||
bool autonomy = 5; // 框架自动化
|
||||
}
|
||||
|
|
121
errcode.go
121
errcode.go
|
@ -1,47 +1,74 @@
|
|||
package coco
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const UnknownError = "unknown"
|
||||
|
||||
const (
|
||||
// ErrNil 正常
|
||||
ErrNil = 0
|
||||
// ErrSystemError 系统错误
|
||||
ErrSystemError = -1
|
||||
// ErrProcessPanic 服务PANIC
|
||||
ErrProcessPanic = -10
|
||||
)
|
||||
// ErrorNil 正常
|
||||
ErrorNil = 0
|
||||
// ErrorInternalServer 系统错误
|
||||
ErrorInternalServer = 500
|
||||
// ErrorNotImplemented 方法没有实现
|
||||
ErrorNotImplemented = 501
|
||||
// ErrorBadGateway 网关错误
|
||||
ErrorBadGateway = 502
|
||||
// ErrorServiceUnavailable 服务不可用
|
||||
ErrorServiceUnavailable = 503
|
||||
// ErrorGatewayTimeout 网关超时
|
||||
ErrorGatewayTimeout = 504
|
||||
// ErrorBadRequest 请求参数无效
|
||||
ErrorBadRequest = 400
|
||||
// ErrorUnauthorized 未授权访问
|
||||
ErrorUnauthorized = 401
|
||||
// ErrorPaymentRequired 缺少参数
|
||||
ErrorPaymentRequired = 402
|
||||
// ErrorForbidden 禁止访问
|
||||
ErrorForbidden = 403
|
||||
// ErrorNotFound 找不到记录
|
||||
ErrorNotFound = 404
|
||||
// ErrorMethodNotAllowed 请求不被允许
|
||||
ErrorMethodNotAllowed = 405
|
||||
// ErrorNotAcceptable 不被接受的请求
|
||||
ErrorNotAcceptable = 406
|
||||
// ErrorProxyAuthenticationRequired 代理需要授权
|
||||
ErrorProxyAuthenticationRequired = 407
|
||||
// ErrorRequestTimeout 请求超时
|
||||
ErrorRequestTimeout = 408
|
||||
// ErrorConflict 资源冲突
|
||||
ErrorConflict = 409
|
||||
|
||||
const (
|
||||
// ErrInvalidArg 请求参数无效
|
||||
ErrInvalidArg = 1001
|
||||
// ErrRecordNotFound 找不到记录
|
||||
ErrRecordNotFound = 1002
|
||||
// ErrConnectTimeout 连接超时
|
||||
ErrConnectTimeout = 1003
|
||||
// ErrFreqLimit 频率限制 [业务级]
|
||||
ErrFreqLimit = 1004
|
||||
// ErrRequestBroken 请求熔断
|
||||
ErrRequestBroken = 1005
|
||||
// ErrRequestRateLimit 请求限流 [服务级]
|
||||
ErrRequestRateLimit = 1006
|
||||
// ErrParamEmpty 请求参数为空
|
||||
ErrParamEmpty = 1007
|
||||
// ErrorFreqLimit 路由频率限制 [业务级]
|
||||
ErrorFreqLimit = 1004
|
||||
// ErrorRequestBroken 请求熔断
|
||||
ErrorRequestBroken = 1005
|
||||
// ErrorRequestRateLimit 请求流控 [服务级]
|
||||
ErrorRequestRateLimit = 1006
|
||||
// ErrorParamEmpty 请求参数为空
|
||||
ErrorParamEmpty = 1007
|
||||
)
|
||||
|
||||
var (
|
||||
errCodeMap = map[int32]string{
|
||||
ErrNil: "ok",
|
||||
ErrSystemError: "system error",
|
||||
ErrProcessPanic: "process panic",
|
||||
ErrInvalidArg: "invalid arg",
|
||||
ErrRecordNotFound: "record not found",
|
||||
ErrConnectTimeout: "connect timeout",
|
||||
ErrFreqLimit: "request freq limit",
|
||||
ErrRequestBroken: "request is broken",
|
||||
ErrRequestRateLimit: "request rate is limited",
|
||||
ErrParamEmpty: "request param is empty",
|
||||
ErrorNil: "ok",
|
||||
ErrorInternalServer: "internal server error",
|
||||
ErrorNotImplemented: "method not implemented",
|
||||
ErrorBadGateway: "bad gateway",
|
||||
ErrorServiceUnavailable: "service unavailable",
|
||||
ErrorGatewayTimeout: "gateway timeout",
|
||||
ErrorBadRequest: "bad request",
|
||||
ErrorUnauthorized: "unauthorized",
|
||||
ErrorPaymentRequired: "payment required",
|
||||
ErrorForbidden: "forbidden",
|
||||
ErrorNotFound: "not found",
|
||||
ErrorMethodNotAllowed: "method not allowed",
|
||||
ErrorNotAcceptable: "not acceptable",
|
||||
ErrorProxyAuthenticationRequired: "proxy authentication is required",
|
||||
ErrorRequestTimeout: "request timeout",
|
||||
ErrorConflict: "conflict",
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -49,48 +76,42 @@ func (m *ErrMsg) Error() string {
|
|||
return fmt.Sprintf("err_code: %d, err_msg: %s", m.ErrCode, m.ErrMsg)
|
||||
}
|
||||
|
||||
func RegisterError(m map[int32]string) {
|
||||
func RegisterErrorCode(m map[int32]string) {
|
||||
for k, v := range m {
|
||||
errCodeMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// GetErrMsg 基于错误码返回错误信息
|
||||
func GetErrMsg(errCode int32) string {
|
||||
if errCode == 0 {
|
||||
return "success"
|
||||
}
|
||||
|
||||
// GetErrMsgMsg 基于错误码返回错误信息
|
||||
func GetErrMsgMsg(errCode int32) string {
|
||||
msg, ok := errCodeMap[errCode]
|
||||
if ok {
|
||||
return msg
|
||||
}
|
||||
if errCode < 0 {
|
||||
return "system error"
|
||||
}
|
||||
|
||||
return UnknownError
|
||||
}
|
||||
|
||||
// CreateError 基于错误码返回错误信息
|
||||
func CreateError(errCode int32) *ErrMsg {
|
||||
return &ErrMsg{ErrCode: errCode, ErrMsg: errCodeMap[errCode]}
|
||||
// GetErrMsg 基于错误码返回错误信息
|
||||
func GetErrMsg(errCode int32) *ErrMsg {
|
||||
return &ErrMsg{ErrCode: errCode, ErrMsg: GetErrMsgMsg(errCode)}
|
||||
}
|
||||
|
||||
// GetErrCode 获取错误码 默认1 业务错误
|
||||
func GetErrCode(err error) int {
|
||||
// GetErrMsgCode 获取错误码 默认1 业务错误
|
||||
func GetErrMsgCode(err error) int {
|
||||
if err == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if p, ok := err.(*ErrMsg); ok {
|
||||
var p *ErrMsg
|
||||
if errors.As(err, &p) {
|
||||
return int(p.ErrCode)
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// CreateErrorWithMsg 自定义创建错误 如果错误码已提前注册 errMsg将失效
|
||||
// CreateErrorWithMsg 自定义创建错误
|
||||
func CreateErrorWithMsg(errCode int32, errMsg string) *ErrMsg {
|
||||
return &ErrMsg{ErrCode: errCode, ErrMsg: errMsg, Autonomy: true}
|
||||
}
|
||||
|
|
36
go.mod
36
go.mod
|
@ -3,36 +3,36 @@ module gitter.top/coco/coco
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.5
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-playground/validator/v10 v10.15.5
|
||||
github.com/gorilla/schema v1.2.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/go-playground/validator/v10 v10.19.0
|
||||
github.com/gorilla/schema v1.3.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
google.golang.org/protobuf v1.31.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.10.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.3 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/arch v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
@ -2,6 +2,7 @@ package coco
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -10,11 +11,10 @@ import (
|
|||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
json "github.com/bytedance/sonic"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gorilla/schema"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -33,39 +33,56 @@ type Result struct {
|
|||
// 只能通过NewRegister()进行实例化 否则会panic
|
||||
type Register struct {
|
||||
// GET参数解析器
|
||||
queryDecoder *schema.Decoder
|
||||
engine *gin.Engine
|
||||
addr string
|
||||
queryDecoder *schema.Decoder
|
||||
engine *gin.Engine
|
||||
addr string
|
||||
defaultContentType string
|
||||
paramsValidate bool
|
||||
}
|
||||
|
||||
type RegisterOptions func(register *Register)
|
||||
|
||||
// WithGinMode set gin router mode
|
||||
// WithGinMode 设置运行模式
|
||||
func WithGinMode(mode string) RegisterOptions {
|
||||
return func(register *Register) {
|
||||
gin.SetMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecovery returns a middleware that recovers from any panics and writes a 500 if there was one.
|
||||
// WithRecovery 自动处理panic异常
|
||||
func WithRecovery() RegisterOptions {
|
||||
return func(register *Register) {
|
||||
register.engine.Use(gin.Recovery())
|
||||
}
|
||||
}
|
||||
|
||||
// WithCors 设置跨域
|
||||
func WithCors() RegisterOptions {
|
||||
return func(register *Register) {
|
||||
register.engine.Use(CorsFilter())
|
||||
}
|
||||
}
|
||||
|
||||
// WithListenAddress 设置监听地址
|
||||
func WithListenAddress(addr string) RegisterOptions {
|
||||
return func(register *Register) {
|
||||
register.addr = addr
|
||||
}
|
||||
}
|
||||
|
||||
// WithDisableRequestParamsValidate 是否默认关闭请求参数校验
|
||||
func WithDisableRequestParamsValidate() RegisterOptions {
|
||||
return func(register *Register) {
|
||||
register.paramsValidate = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithDefaultContentType(ct string) RegisterOptions {
|
||||
return func(register *Register) {
|
||||
register.defaultContentType = ct
|
||||
}
|
||||
}
|
||||
|
||||
// NewRegister 实例化注册器
|
||||
func NewRegister() *Register {
|
||||
var register = &Register{queryDecoder: schema.NewDecoder()}
|
||||
|
@ -226,7 +243,7 @@ func (r *Register) getCallFunc(rFunc, rGroup reflect.Value) (gin.HandlerFunc, er
|
|||
|
||||
// 第二返回参数是否是error
|
||||
if returnType := typ.Out(1); returnType != reflect.TypeOf((*error)(nil)).Elem() {
|
||||
return nil, errors.Errorf("method : %v , returns[1] %v not error",
|
||||
return nil, fmt.Errorf("method : %v , returns[1] %v not error",
|
||||
runtime.FuncForPC(rFunc.Pointer()).Name(), returnType.String())
|
||||
}
|
||||
|
||||
|
@ -252,7 +269,7 @@ func (r *Register) getCallFunc(rFunc, rGroup reflect.Value) (gin.HandlerFunc, er
|
|||
err := r.bindAndValidate(c, req.Interface())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, Result{
|
||||
ErrCode: ErrInvalidArg,
|
||||
ErrCode: ErrorBadRequest,
|
||||
ErrMsg: err.Error(),
|
||||
})
|
||||
return
|
||||
|
@ -260,66 +277,21 @@ func (r *Register) getCallFunc(rFunc, rGroup reflect.Value) (gin.HandlerFunc, er
|
|||
|
||||
var returnValues = rFunc.Call([]reflect.Value{rGroup, reflect.ValueOf(&Context{Context: c}), req})
|
||||
|
||||
// 设置缺省 Content-Type
|
||||
if c.Writer.Header().Get("Content-Type") == "" {
|
||||
c.Writer.Header().Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
// 重定向的情况
|
||||
if c.Writer.Status() == http.StatusFound || c.Writer.Status() == http.StatusMovedPermanently {
|
||||
if r.isStatusFoundOrMoved(c) {
|
||||
return
|
||||
}
|
||||
|
||||
// 传输文件直接下载的情况
|
||||
if !strings.Contains(c.Writer.Header().Get("Content-Type"), "application/json") {
|
||||
if !r.isApplicationJson(c) {
|
||||
return
|
||||
}
|
||||
|
||||
if returnValues != nil {
|
||||
resp := returnValues[0].Interface()
|
||||
rerr := returnValues[1].Interface()
|
||||
// 设置缺省 Content-Type
|
||||
r.setDefaultContentType(c)
|
||||
|
||||
if rerr == nil {
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
respData, _ := jsoniter.Marshal(Result{
|
||||
ErrCode: ErrNil,
|
||||
ErrMsg: "ok",
|
||||
Data: resp,
|
||||
})
|
||||
_, _ = c.Writer.Write(respData)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
var errCode int
|
||||
var errMsg string
|
||||
|
||||
var isAutonomy bool
|
||||
if reflect.TypeOf(rerr).String() == "*core.ErrMsg" {
|
||||
e := rerr.(*ErrMsg)
|
||||
if e.Autonomy {
|
||||
err = e
|
||||
errCode = int(e.ErrCode)
|
||||
errMsg = e.ErrMsg
|
||||
isAutonomy = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isAutonomy {
|
||||
err = rerr.(error)
|
||||
errCode = GetErrCode(err)
|
||||
errMsg = GetErrMsg(int32(errCode))
|
||||
}
|
||||
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
respData, _ := jsoniter.Marshal(Result{
|
||||
ErrCode: errCode,
|
||||
ErrMsg: errMsg,
|
||||
Data: resp,
|
||||
})
|
||||
_, _ = c.Writer.Write(respData)
|
||||
return
|
||||
}
|
||||
// 处理返回值
|
||||
r.processReturnValue(c, returnValues)
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -332,6 +304,9 @@ func (r *Register) mergeRequestParam(a, b map[string]interface{}) map[string]int
|
|||
|
||||
// bindAndValidate 绑定并校验参数
|
||||
func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
|
||||
if !r.paramsValidate {
|
||||
return nil
|
||||
}
|
||||
// 非 application/json 直接透传
|
||||
if c.GetHeader("Content-Type") != "application/json" {
|
||||
// 如果只有query有数据,则获取query中的参数
|
||||
|
@ -345,7 +320,7 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
|
|||
return nil
|
||||
}
|
||||
bodyBytes, _ := io.ReadAll(c.Request.Body)
|
||||
c.Request.Body.Close()
|
||||
_ = c.Request.Body.Close()
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
|
||||
// 如果只有query有数据,则获取query中的参数
|
||||
|
@ -358,7 +333,7 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
|
|||
}
|
||||
// 如果只有body中有数据,获取body中的参数
|
||||
if len(c.Request.URL.Query()) == 0 && len(bodyBytes) != 0 {
|
||||
err := jsoniter.Unmarshal(bodyBytes, req)
|
||||
err := json.Unmarshal(bodyBytes, req)
|
||||
if err != nil {
|
||||
logrus.Errorf("unmarshal body failed: %+v", err)
|
||||
return err
|
||||
|
@ -373,18 +348,18 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
|
|||
return err
|
||||
}
|
||||
var bodyMap = make(map[string]interface{})
|
||||
err = jsoniter.Unmarshal(bodyBytes, bodyMap)
|
||||
err = json.Unmarshal(bodyBytes, bodyMap)
|
||||
if err != nil {
|
||||
logrus.Errorf("unmarshal body failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
mergeMap := r.mergeRequestParam(queryMap, bodyMap)
|
||||
body, err := jsoniter.Marshal(mergeMap)
|
||||
body, err := json.Marshal(mergeMap)
|
||||
if err != nil {
|
||||
logrus.Errorf("merge query and body failed: %v", err)
|
||||
return err
|
||||
}
|
||||
if err := jsoniter.Unmarshal(body, req); err != nil {
|
||||
if err := json.Unmarshal(body, req); err != nil {
|
||||
logrus.Errorf("unmarshal query and body failed: %v", err)
|
||||
return err
|
||||
}
|
||||
|
@ -404,7 +379,8 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
|
|||
|
||||
err := validate.Struct(req)
|
||||
if err != nil {
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||
var invalidValidationError *validator.InvalidValidationError
|
||||
if errors.As(err, &invalidValidationError) {
|
||||
logrus.Errorf("validate failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
@ -418,6 +394,56 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// processReturnValue 处理返回值
|
||||
func (r *Register) processReturnValue(c *gin.Context, returnValues []reflect.Value) {
|
||||
if len(returnValues) != 2 {
|
||||
return
|
||||
}
|
||||
resp := returnValues[0].Interface()
|
||||
rerr := returnValues[1].Interface()
|
||||
|
||||
if rerr == nil {
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
respData, _ := json.Marshal(Result{
|
||||
ErrCode: ErrorNil,
|
||||
ErrMsg: GetErrMsgMsg(ErrorNil),
|
||||
Data: resp,
|
||||
})
|
||||
_, _ = c.Writer.Write(respData)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
var errCode int
|
||||
var errMsg string
|
||||
|
||||
var isAutonomy bool
|
||||
if reflect.TypeOf(rerr).String() == "*core.ErrMsg" {
|
||||
e := rerr.(*ErrMsg)
|
||||
if e.Autonomy {
|
||||
err = e
|
||||
errCode = int(e.ErrCode)
|
||||
errMsg = e.ErrMsg
|
||||
isAutonomy = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isAutonomy {
|
||||
err = rerr.(error)
|
||||
errCode = GetErrMsgCode(err)
|
||||
errMsg = GetErrMsgMsg(int32(errCode))
|
||||
}
|
||||
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
respData, _ := json.Marshal(Result{
|
||||
ErrCode: errCode,
|
||||
ErrMsg: errMsg,
|
||||
Data: resp,
|
||||
})
|
||||
_, _ = c.Writer.Write(respData)
|
||||
return
|
||||
}
|
||||
|
||||
// CorsFilter 跨域过滤器
|
||||
func CorsFilter() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
@ -444,3 +470,20 @@ func ResponseHtmlHeader() gin.HandlerFunc {
|
|||
c.Writer.Header().Set("Content-Type", "text/html")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Register) setDefaultContentType(c *gin.Context) {
|
||||
if r.defaultContentType == "" {
|
||||
r.defaultContentType = "application/json"
|
||||
}
|
||||
if c.Writer.Header().Get("Content-Type") == "" {
|
||||
c.Writer.Header().Set("Content-Type", r.defaultContentType)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Register) isApplicationJson(c *gin.Context) bool {
|
||||
return c.Writer.Header().Get("Content-Type") == "application/json"
|
||||
}
|
||||
|
||||
func (r *Register) isStatusFoundOrMoved(c *gin.Context) bool {
|
||||
return c.Writer.Status() == http.StatusFound || c.Writer.Status() == http.StatusMovedPermanently
|
||||
}
|
||||
|
|
|
@ -27,8 +27,9 @@ func TestRegister_getCallFunc(t *testing.T) {
|
|||
|
||||
func TestNewRegister(t *testing.T) {
|
||||
var register = NewRegister()
|
||||
register.DefaultRouter(WithListenAddress(""), WithGinMode(gin.ReleaseMode), WithCors(), WithRecovery())
|
||||
register.PreRun(nil)
|
||||
register.DefaultRouter(WithListenAddress("localhost:8080"), WithGinMode(gin.ReleaseMode), WithCors(), WithRecovery())
|
||||
|
||||
// register.PreRun(nil)
|
||||
// protoc core/file_module.proto --coco_out=core --go_out=core
|
||||
//reg.RegisterStruct(AutoGenXXXRouterMap, &XXX{})
|
||||
register.Run()
|
||||
|
|
174
utils/reflect.go
174
utils/reflect.go
|
@ -1,174 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ReflectGet(obj interface{}, path string, failHint *string) (res interface{}, success bool) {
|
||||
setFailHint := func(hint string) {
|
||||
if failHint != nil {
|
||||
*failHint = hint
|
||||
}
|
||||
}
|
||||
for obj != nil && path != "" {
|
||||
v := reflect.ValueOf(obj)
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Struct {
|
||||
setFailHint("not struct type")
|
||||
break
|
||||
}
|
||||
|
||||
var fieldName string
|
||||
pos := strings.IndexByte(path, '.')
|
||||
if pos < 0 {
|
||||
fieldName = path
|
||||
path = ""
|
||||
} else {
|
||||
fieldName = path[:pos]
|
||||
path = path[pos+1:]
|
||||
}
|
||||
|
||||
f := v.FieldByName(fieldName)
|
||||
if !f.IsValid() {
|
||||
setFailHint(fmt.Sprintf("%s not found", fieldName))
|
||||
break
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
res = f.Interface()
|
||||
success = true
|
||||
break
|
||||
}
|
||||
|
||||
obj = f.Interface()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReflectGetInt(obj interface{}, path string, failHint *string) (res int, success bool) {
|
||||
setFailHint := func(hint string) {
|
||||
if failHint != nil {
|
||||
*failHint = hint
|
||||
}
|
||||
}
|
||||
|
||||
var i interface{}
|
||||
i, success = ReflectGet(obj, path, failHint)
|
||||
if !success {
|
||||
return
|
||||
}
|
||||
switch v := i.(type) {
|
||||
case int:
|
||||
res = v
|
||||
success = true
|
||||
case int32:
|
||||
res = int(v)
|
||||
success = true
|
||||
default:
|
||||
setFailHint(fmt.Sprintf("type not match: %s", reflect.TypeOf(i).String()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ReflectGetStr(obj interface{}, path string, failHint *string) (res string, success bool) {
|
||||
setFailHint := func(hint string) {
|
||||
if failHint != nil {
|
||||
*failHint = hint
|
||||
}
|
||||
}
|
||||
|
||||
var i interface{}
|
||||
i, success = ReflectGet(obj, path, failHint)
|
||||
if !success {
|
||||
return
|
||||
}
|
||||
switch v := i.(type) {
|
||||
case string:
|
||||
res = v
|
||||
success = true
|
||||
case []byte:
|
||||
res = string(v)
|
||||
success = true
|
||||
default:
|
||||
setFailHint(fmt.Sprintf("type not match: %s", reflect.TypeOf(i).String()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Interface2Int(i interface{}) int {
|
||||
vo := reflect.ValueOf(i)
|
||||
vk := vo.Kind()
|
||||
switch vk {
|
||||
case reflect.Uint, reflect.Uint32, reflect.Uint64, reflect.Uint8, reflect.Uint16:
|
||||
return int(vo.Uint())
|
||||
}
|
||||
return int(vo.Int())
|
||||
}
|
||||
|
||||
func Interface2String(i interface{}) string {
|
||||
vo := reflect.ValueOf(i)
|
||||
if vo.Kind() != reflect.String {
|
||||
log.Infof("expected string type, but got %v", vo.Type())
|
||||
panic("expected string type")
|
||||
}
|
||||
return vo.String()
|
||||
}
|
||||
|
||||
func EnsureIsSliceOrArray(obj interface{}) (res reflect.Value) {
|
||||
vo := reflect.ValueOf(obj)
|
||||
for vo.Kind() == reflect.Ptr || vo.Kind() == reflect.Interface {
|
||||
vo = vo.Elem()
|
||||
}
|
||||
k := vo.Kind()
|
||||
if k != reflect.Slice && k != reflect.Array {
|
||||
panic(fmt.Sprintf("obj required slice or array type, but got %v", vo.Type()))
|
||||
}
|
||||
res = vo
|
||||
return
|
||||
}
|
||||
|
||||
func EnsureIsMapType(m reflect.Value, keyType, valType reflect.Type) {
|
||||
if m.Kind() != reflect.Map {
|
||||
panic(fmt.Sprintf("required map type, but got %v", m.Type()))
|
||||
}
|
||||
|
||||
t := m.Type()
|
||||
if t.Key() != keyType {
|
||||
panic(fmt.Sprintf("map key type not equal, %v != %v", t.Key(), keyType))
|
||||
}
|
||||
|
||||
if t.Elem() != valType {
|
||||
panic(fmt.Sprintf("map val type not equal, %v != %v", t.Elem(), valType))
|
||||
}
|
||||
}
|
||||
|
||||
func ClearSlice(ptr interface{}) {
|
||||
vo := reflect.ValueOf(ptr)
|
||||
if vo.Kind() != reflect.Ptr {
|
||||
panic("required ptr to slice type")
|
||||
}
|
||||
for vo.Kind() == reflect.Ptr {
|
||||
vo = vo.Elem()
|
||||
}
|
||||
if vo.Kind() != reflect.Slice {
|
||||
panic("required ptr to slice type")
|
||||
}
|
||||
vo.Set(reflect.MakeSlice(vo.Type(), 0, 0))
|
||||
}
|
||||
|
||||
func GetSliceLen(i interface{}) int {
|
||||
vo := reflect.ValueOf(i)
|
||||
for vo.Kind() == reflect.Ptr {
|
||||
vo = vo.Elem()
|
||||
}
|
||||
if vo.Kind() != reflect.Slice && vo.Kind() != reflect.Array {
|
||||
panic("required slice or array type")
|
||||
}
|
||||
return vo.Len()
|
||||
}
|
Loading…
Reference in New Issue