-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrouter.go
182 lines (158 loc) · 3.97 KB
/
router.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package zebra
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"regexp"
"strings"
)
// 一个路由路径中间件
type route struct {
path string // 路由配置的原始路径
handlers []func(c *Captain) // 处理器
method int // http method
pattern *regexp.Regexp // 匹配实际path用的正则
router *Router // 所属Router
}
// 路由中间件 Router .
type Router struct {
routers []*route
captain *Captain
}
// 创建 Router 中间件
func NewRouter() *Router {
router := Router{
routers: make([]*route, 0),
}
router.captain = newCaptain(&router)
return &router
}
func (r *route) excute(url string, method int) {
captain := r.router.captain
if (r.method == MethodAny || r.method == method) &&
(r.path == url || makePathParams(url, r, captain)) {
for _, h := range r.handlers {
h(captain)
}
}
}
func (r *Router) Excute(c *Context) bool {
if len(r.routers) > 0 {
for _, route := range r.routers {
route.excute(c.Urlpath, c.Method)
}
if r.captain != nil && len(r.captain.output) > 0 {
r.captain.write(c)
}
}
return true
}
func (r *Router) Any(path string, h ...func(c *Captain)) {
r.addRoute(MethodAny, path, h)
}
func (r *Router) Get(path string, h ...func(c *Captain)) {
r.addRoute(MethodGet, path, h)
}
func (r *Router) Post(path string, h ...func(c *Captain)) {
r.addRoute(MethodPost, path, h)
}
func (r *Router) Put(path string, h ...func(c *Captain)) {
r.addRoute(MethodPut, path, h)
}
func (r *Router) Delete(path string, h ...func(c *Captain)) {
r.addRoute(MethodDelete, path, h)
}
func (r *Router) Options(path string, h ...func(c *Captain)) {
r.addRoute(MethodOptions, path, h)
}
func (r *Router) register(route *route) {
route.router = r
r.routers = append(r.routers, route)
}
func (r *Router) addRoute(method int, path string, handlers []func(c *Captain)) *route {
route := newRoute(method, path, handlers)
r.register(route)
return route
}
var (
regAdvanced = regexp.MustCompile(`:[A-Za-z_]+[0-9]*\{.+\}`)
regCommon = regexp.MustCompile(`:[A-Za-z_]+[0-9]*`)
)
// 辅助方法,创建route
func newRoute(method int, path string, handlers []func(c *Captain)) *route {
r := route{
path: path,
method: method,
handlers: handlers,
}
path = regAdvanced.ReplaceAllStringFunc(path, func(m string) string {
sp := strings.Index(m, "{")
regStr := m[sp+1 : len(m)-1]
_, err := regexp.Compile(regStr)
if err != nil {
panic("路由配置中使用了错误的正则: " + regStr)
}
return fmt.Sprintf(`(?P<%s>%s)`, m[1:sp], regStr)
})
path = regCommon.ReplaceAllStringFunc(path, func(m string) string {
return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:])
})
path += `\/?`
r.pattern = regexp.MustCompile(path)
return &r
}
func makePathParams(reqUrl string, route *route, c *Captain) (ret bool) {
matches := route.pattern.FindStringSubmatch(reqUrl)
if len(matches) > 0 && matches[0] == reqUrl {
for i, name := range route.pattern.SubexpNames() {
if len(name) > 0 {
c.paths[name] = matches[i]
ret = true
}
}
}
return
}
// Router 上下文对象
type Captain struct {
router *Router
paths map[string]string
exporter
}
func newCaptain(router *Router) *Captain {
return &Captain{
paths: make(map[string]string),
router: router,
}
}
func (c *Captain) Path(pathname string) string {
return c.paths[pathname]
}
func (c *Captain) write(cxt *Context) {
res := cxt.ResponseWriter()
res.Header().Set("Content-Type", c.mimeType)
res.Header().Set("X-Powered-By", "Zebra")
if c.status == 0 {
c.status = http.StatusOK
}
//res.WriteHeader(c.status)
res.Write(c.output)
}
// 输出方法
type exporter struct {
output []byte
mimeType string
status int
}
func (e *exporter) Status(code int) {
e.status = code
}
func (e *exporter) WriteJSON(data interface{}) {
result, err := json.Marshal(data)
if err != nil {
panic("JSON解析时遇到无法解析的数据类型: " + reflect.TypeOf(data).Name())
}
e.output = result
e.mimeType = "application/json"
}