-
Notifications
You must be signed in to change notification settings - Fork 0
/
entry.go
148 lines (132 loc) · 3.62 KB
/
entry.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package goscf
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/tencentyun/scf-go-lib/cloudfunction"
"github.com/tencentyun/scf-go-lib/events"
"net/http"
"net/url"
"reflect"
"strings"
)
type (
HandlerFunc func(ctx context.Context) error
MiddlewareFunc func(next HandlerFunc) HandlerFunc
)
func apiWrapper(handler interface{}, middleware ...MiddlewareFunc) interface{} {
handlerValue := reflect.ValueOf(handler)
handlerType := reflect.TypeOf(handler)
if handlerType.Kind() != reflect.Func {
panic(fmt.Errorf("handler kind %s is not %s", handlerType.Kind(), reflect.Func))
}
return func(ctx context.Context, req events.APIGatewayRequest) (events.APIGatewayResponse, error) {
res := events.APIGatewayResponse{
StatusCode: http.StatusOK,
Headers: map[string]string{},
IsBase64Encoded: false,
}
if handler == nil {
return res, errors.New("handler is nil")
}
// 通过反射调用处理函数
h := func(ctx context.Context) error {
res := ResponseFromContext(ctx)
var args []reflect.Value
args = append(args, reflect.ValueOf(ctx))
if handlerType.NumIn() == 2 {
eventType := handlerType.In(handlerType.NumIn() - 1)
event := reflect.New(eventType)
if req.Method == http.MethodGet {
err := bindData(event.Interface(), req.QueryString, "json")
if err != nil {
return err
}
} else {
data := []byte(req.Body)
// 转换FORM数据
cType := Header(req.Headers).Get("content-type")
if cType == "" {
cType = http.DetectContentType(data)
}
if strings.Contains(cType, "form") {
params, err := url.ParseQuery(req.Body)
if err != nil {
return err
}
m := map[string]interface{}{}
for k, v := range params {
if len(v) == 1 {
m[k] = v[0]
} else {
m[k] = "[" + strings.Join(v, " ") + "]"
}
}
data, err = json.Marshal(m)
if err != nil {
return err
}
}
// 绑定JSON数据
if err := json.Unmarshal(data, event.Interface()); err != nil {
return err
}
}
args = append(args, event.Elem())
}
response := handlerValue.Call(args)
if len(response) > 0 {
// 检查是否有错误
if len(response) == 2 && !response[1].IsNil() {
return response[1].Interface().(error)
} else {
resData := response[0]
if resData.Kind() == reflect.Interface {
resData = resData.Elem()
}
if resData.Kind() == reflect.String {
// 如果是字符串则不转换
res.Headers["Content-Type"] = "application/x-javascript;charset=utf-8"
res.Body = resData.String()
} else {
// 如果是struct则转为json
res.Headers["Content-Type"] = "application/json;charset=utf-8"
var data interface{}
if resData.IsValid() {
data = resData.Interface()
}
payload, err := json.Marshal(map[string]interface{}{
"data": data,
})
if err != nil {
return err
}
res.Body = string(payload)
}
}
}
return nil
}
// 应用中间件
for i := len(middleware) - 1; i >= 0; i-- {
h = middleware[i](h)
}
// 执行函数
ctx = ContextWithRequest(ctx, &req)
ctx = ContextWithResponse(ctx, &res)
ctx = ContextWithIp(ctx, req.Context.SourceIP)
if err := h(ctx); err != nil {
payload, _ := json.Marshal(map[string]interface{}{
"error": err.Error(),
})
res.Body = string(payload)
return res, nil
}
return res, nil
}
}
func APIGateway(handler interface{}, middleware ...MiddlewareFunc) {
wrapperHandler := apiWrapper(handler, middleware...)
cloudfunction.Start(wrapperHandler)
}