-
Notifications
You must be signed in to change notification settings - Fork 1
/
handler.go
117 lines (97 loc) · 2.95 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package sgin
import (
"errors"
"reflect"
"strings"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
type Handler any // func(*Ctx[, T]) -> T | (int, T) | (T, error)
func handler(r *Route, a ...Handler) (handlers []gin.HandlerFunc) {
for _, f := range a {
switch ginHandler := f.(type) {
case gin.HandlerFunc:
handlers = append(handlers, ginHandler)
continue
case func(*gin.Context):
handlers = append(handlers, ginHandler)
continue
}
handler := reflect.ValueOf(f)
handlerType := handler.Type()
handlers = append(handlers, func(ginCtx *gin.Context) {
ctx, _ := ginCtx.Keys["_baa/sgin/ctxkey"].(*Ctx)
if ctx == nil {
ctx = newCtx(ginCtx, r.engine) // 创建 *sgin.Ctx
ginCtx.Set("_baa/sgin/ctxkey", ctx) // 保存 *sgin.Ctx
}
inputParam := []reflect.Value{reflect.ValueOf(ctx)} // *Ctx[, T]
if handlerType.NumIn() == 2 { // 如果处理函数有两个参数
value, err := bind(ginCtx, handlerType.In(1)) // 创建并绑定请求结构体
if err != nil { // 处理错误
ginCtx.Abort() // 停止请求链
_ = r.engine.config.ErrorHandler(ctx, &Error{Message: err.Error()}) // 返回错误
return
}
inputParam = append(inputParam, value)
}
ctx.response(handler.Call(inputParam))
})
}
return
}
// bind 绑定请求结构体
func bind(c *gin.Context, T reflect.Type) (value reflect.Value, err error) {
isStructPtr := T.Kind() == reflect.Ptr
if isStructPtr {
T = T.Elem()
}
value = reflect.New(T) // 创建结构体 *T 的 reflect.Value
ptr := value.Interface() // 结构体指针
ct := c.ContentType()
if c.Request.Method == "GET" || ct == gin.MIMEPOSTForm || strings.HasPrefix(ct, gin.MIMEMultipartPOSTForm) {
err = c.ShouldBind(ptr)
} else if ct == gin.MIMEJSON {
err = c.ShouldBindBodyWith(ptr, binding.JSON)
} else if ct == gin.MIMEXML {
err = c.ShouldBindBodyWith(ptr, binding.XML)
}
var vErrs validator.ValidationErrors
if errors.As(err, &vErrs) {
for _, e := range vErrs {
if field, ok := T.FieldByName(e.Field()); ok {
if failtip := field.Tag.Get("failtip"); failtip != "" {
err = errors.New(failtip)
break
}
}
}
}
if !isStructPtr {
value = value.Elem()
}
return
}
// response 返回响应 (处理函数的给定返回值)
// 返回值可以为:T | (int, T) | (T, error)
func (c *Ctx) response(result []reflect.Value) {
if result == nil { // 没有返回值
return
}
first := result[0].Interface() // 第一个返回值
if len(result) == 1 {
c.autoFormat(first)
return
}
second := result[1].Interface() // 第二个返回值
if statusCode, ok := first.(int); ok { // (int, T)
c.Status(statusCode).autoFormat(second)
return
}
if err, ok := second.(error); ok { // (T, error)
c.autoFormat(err)
return
}
c.autoFormat(first) // 没有错误,返回 T
}