Skip to content

Commit

Permalink
refactor: 调整中间件的调用顺序
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed May 20, 2024
1 parent 2f4db8b commit 1b632f6
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 42 deletions.
2 changes: 1 addition & 1 deletion internal/tree/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (n *node[T]) addMethods(h T, pattern string, ms []types.MiddlewareOf[T], me
}

if _, found := n.handlers[methodNotAllowed]; !found {
n.handlers[methodNotAllowed] = n.root.methodNotAllowedBuilder(n)
n.handlers[methodNotAllowed] = ApplyMiddleware(n.root.methodNotAllowedBuilder(n), "", pattern, ms...)
}

n.buildMethods()
Expand Down
4 changes: 2 additions & 2 deletions internal/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func New[T any](lock bool, i *syntax.Interceptors, notFound T, trace bool, metho
// Add 添加路由项
//
// methods 可以为空,表示添所有支持的请求方法,其中的 HEAD 和 OPTIONS 不受控。
func (tree *Tree[T]) Add(pattern string, h T, middlewares []types.MiddlewareOf[T], methods ...string) error {
func (tree *Tree[T]) Add(pattern string, h T, ms []types.MiddlewareOf[T], methods ...string) error {
if err := tree.checkAmbiguous(pattern); err != nil {
return err
}
Expand All @@ -104,7 +104,7 @@ func (tree *Tree[T]) Add(pattern string, h T, middlewares []types.MiddlewareOf[T
if len(methods) == 0 {
methods = addAny
}
return n.addMethods(h, pattern, middlewares, methods...)
return n.addMethods(h, pattern, ms, methods...)
}

func (tree *Tree[T]) checkAmbiguous(pattern string) error {
Expand Down
12 changes: 9 additions & 3 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ func (r *RouterOf[T]) Routes() map[string][]string { return r.tree.Routes() }
func (r *RouterOf[T]) Remove(pattern string, methods ...string) { r.tree.Remove(pattern, methods...) }

// Use 使用中间件
//
// 对于中间件的使用,除了此方法,还可以 [RouterOf.Prefix]、[RouterOf.Resource]、[PrefixOf.Prefix]
// 以及添加路由项时指定。调用顺序如下:
// - Get/Delete 等添加路由项的方法;
// - [RouterOf.Prefix]、[RouterOf.Resource]、[PrefixOf.Prefix];
// - [Router.Use];
func (r *RouterOf[T]) Use(m ...types.MiddlewareOf[T]) {
r.middleware = append(r.middleware, m...)
r.tree.ApplyMiddleware(m...)
Expand All @@ -112,7 +118,7 @@ func (r *RouterOf[T]) Use(m ...types.MiddlewareOf[T]) {
// pattern 为路由匹配模式,可以是正则匹配也可以是字符串匹配,
// 若语法不正确,则直接 panic,可以通过 [CheckSyntax] 检测语法的有效性,其它接口也相同;
// m 为应用于当前路由项的中间件;
// methods 该路由项对应的请求方法,如果未指定值,则表示所有支持的请求方法,其中 OPTIONS 和 HEAD 不受控;
// methods 该路由项对应的请求方法,如果未指定值,则表示所有支持的请求方法,其中 OPTIONS、TRACE 和 HEAD 不受控;
func (r *RouterOf[T]) Handle(pattern string, h T, m []types.MiddlewareOf[T], methods ...string) *RouterOf[T] {
m = slices.Concat(m, r.middleware)
if err := r.tree.Add(pattern, h, m, methods...); err != nil {
Expand Down Expand Up @@ -273,7 +279,7 @@ func (p *PrefixOf[T]) URL(strict bool, pattern string, params map[string]string)
//
// m 中间件函数,按顺序调用,会继承 p 的中间件并按在 m 之前;
func (p *PrefixOf[T]) Prefix(prefix string, m ...types.MiddlewareOf[T]) *PrefixOf[T] {
return p.router.Prefix(p.Pattern()+prefix, slices.Concat(p.middleware, m)...)
return p.router.Prefix(p.Pattern()+prefix, slices.Concat(m, p.middleware)...)
}

// Prefix 声明一个 [PrefixOf] 实例
Expand Down Expand Up @@ -351,7 +357,7 @@ func (r *RouterOf[T]) Resource(pattern string, m ...types.MiddlewareOf[T]) *Reso
// pattern 资源地址;
// m 中间件函数,按顺序调用,会继承 p 的中间件并按在 m 之前;
func (p *PrefixOf[T]) Resource(pattern string, m ...types.MiddlewareOf[T]) *ResourceOf[T] {
return p.router.Resource(p.Pattern()+pattern, slices.Concat(p.middleware, m)...)
return p.router.Resource(p.Pattern()+pattern, slices.Concat(m, p.middleware)...)
}

// Router 返回与当前资源关联的 [RouterOf] 实例
Expand Down
54 changes: 19 additions & 35 deletions router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,14 @@ func TestRouterOf_Middleware(t *testing.T) {
def := std.NewRouter("")
a.NotNil(def)
def.Use(tree.BuildTestMiddleware(a, "m1"), tree.BuildTestMiddleware(a, "m2"), tree.BuildTestMiddleware(a, "m3"), tree.BuildTestMiddleware(a, "m4"))
def.Get("/get", rest.BuildHandler(a, 201, "", nil))
def.Get("/get", rest.BuildHandler(a, 201, "", nil), tree.BuildTestMiddleware(a, "m0"))
def.Post("/get", rest.BuildHandler(a, 201, "", nil))

rest.Get(a, "/get").Do(def).Status(201).StringBody("m1m2m3m4")
rest.Post(a, "/get", nil).Do(def).Status(201).StringBody("m1m2m3m4")
rest.Get(a, "/get").Do(def).Status(201).StringBody("m1m2m3m4")
rest.Get(a, "/get").Do(def).Status(201).StringBody("m0m1m2m3m4")
rest.Post(a, "/get", nil).Do(def).Status(201).StringBody("m1m2m3m4")

def.Use(tree.BuildTestMiddleware(a, "m5"), tree.BuildTestMiddleware(a, "m6"))
rest.Get(a, "/get").Do(def).Status(201).StringBody("m1m2m3m4m5m6")
rest.Get(a, "/get").Do(def).Status(201).StringBody("m0m1m2m3m4m5m6")
}

func TestResourceOf(t *testing.T) {
Expand Down Expand Up @@ -247,17 +245,18 @@ func TestRouterOf_Resource(t *testing.T) {
a := assert.New(t, false)
def := std.NewRouter("")
a.NotNil(def)
def.Use(tree.BuildTestMiddleware(a, "d1"))

r1 := def.Resource("/abc/1")
r1 := def.Resource("/abc/1", tree.BuildTestMiddleware(a, "r1"))
a.NotNil(r1)
a.Equal(r1.Router(), def)

r2 := def.Resource("/abc/1")
r2 := def.Resource("/abc/1", tree.BuildTestMiddleware(a, "r1"))
a.NotNil(r2)
a.False(r1 == r2) // 不是同一个 *Resource

r2.Delete(rest.BuildHandler(a, 201, "", nil))
rest.Delete(a, "/abc/1").Do(def).Status(201)
r2.Delete(rest.BuildHandler(a, 201, "-201-", nil), tree.BuildTestMiddleware(a, "d1"))
rest.Delete(a, "/abc/1").Do(def).Status(201).StringBody("-201-d1r1d1")
}

func TestPrefix_Resource(t *testing.T) {
Expand All @@ -272,9 +271,9 @@ func TestPrefix_Resource(t *testing.T) {
r1 := p.Resource("/abc/1", tree.BuildTestMiddleware(a, "r1"), tree.BuildTestMiddleware(a, "r2"))
a.NotNil(r1)

r1.Delete(rest.BuildHandler(a, 201, "-201-", nil))
rest.Delete(a, "/p1/abc/1").Do(def).Status(201).StringBody("-201-p1p2r1r2")
rest.Delete(a, "/p1/abc/1").Do(def).Status(201).StringBody("-201-p1p2r1r2")
r1.Delete(rest.BuildHandler(a, 201, "-201-", nil), tree.BuildTestMiddleware(a, "m1"))
rest.Delete(a, "/p1/abc/1").Do(def).Status(201).StringBody("-201-m1r1r2p1p2")
rest.Delete(a, "/p1/abc/1").Do(def).Status(201).StringBody("-201-m1r1r2p1p2")
}

func TestResourceOf_URL(t *testing.T) {
Expand Down Expand Up @@ -374,7 +373,7 @@ func TestPrefixOf(t *testing.T) {
rest.NewRequest(a, http.MethodOptions, "/p/h/any").Do(r).Status(404)
}

func TestRouterOf_Prefix(t *testing.T) {
func TestPrefixOf_Prefix(t *testing.T) {
t.Run("prefix", func(t *testing.T) {
a := assert.New(t, false)
def := std.NewRouter("", mux.AllowedCORS(3600))
Expand All @@ -384,7 +383,7 @@ func TestRouterOf_Prefix(t *testing.T) {
a.Equal(p.Router(), def)
})

t.Run("prefix with middleware", func(t *testing.T) {
t.Run("empty prefix", func(t *testing.T) {
a := assert.New(t, false)
def := std.NewRouter("", mux.AllowedCORS(3600))
a.NotNil(def)
Expand All @@ -397,42 +396,27 @@ func TestRouterOf_Prefix(t *testing.T) {
rest.Delete(a, "/abc").Do(def).Status(201)
})

t.Run("empty prefix with middleware", func(t *testing.T) {
//
t.Run("prefix 的中间调用顺序", func(t *testing.T) {
a := assert.New(t, false)
def := std.NewRouter("", mux.AllowedCORS(3600))
a.NotNil(def)
def.Use(tree.BuildTestMiddleware(a, "r0"))

p := def.Prefix("/abc")
p := def.Prefix("/abc", tree.BuildTestMiddleware(a, "p1"))
a.Equal(p.Router(), def)

pp := p.Prefix("", tree.BuildTestMiddleware(a, "p1"), tree.BuildTestMiddleware(a, "p2"))
pp := p.Prefix("", tree.BuildTestMiddleware(a, "p2"), tree.BuildTestMiddleware(a, "p3"))
pp.Delete("", rest.BuildHandler(a, 201, "-201-", nil))

rest.Delete(a, "/abc").Do(def).Status(201).StringBody("-201-p1p2")
rest.Delete(a, "/abc").Do(def).Status(201).StringBody("-201-p2p3p1r0")

// Trace
rest.NewRequest(a, http.MethodTrace, "/abc").Do(def).Status(http.StatusMethodNotAllowed)
rest.NewRequest(a, http.MethodTrace, "/abc/not-exists").Do(def).Status(http.StatusNotFound)
})
}

func TestPrefixOf_Prefix(t *testing.T) {
a := assert.New(t, false)
def := std.NewRouter("", mux.AllowedCORS(3600), mux.Trace(true))
a.NotNil(def)

p := def.Prefix("/abc", tree.BuildTestMiddleware(a, "p1"), tree.BuildTestMiddleware(a, "p2"))
pp := p.Prefix("/def", tree.BuildTestMiddleware(a, "pp1"), tree.BuildTestMiddleware(a, "pp2"))
a.Equal(p.Router(), def)
pp.Delete("", rest.BuildHandler(a, 201, "-201-", nil))

rest.Delete(a, "/abc/def").Do(def).Status(201).StringBody("-201-p1p2pp1pp2")

// Trace
rest.NewRequest(a, http.MethodTrace, "/abc/def").Do(def).Status(http.StatusOK)
rest.NewRequest(a, http.MethodTrace, "/abc/not-exists").Do(def).Status(http.StatusOK)
}

func TestPrefixOf_URL(t *testing.T) {
a := assert.New(t, false)
def := std.NewRouter("", mux.AllowedCORS(3600), mux.URLDomain("https://example.com"))
Expand Down
4 changes: 3 additions & 1 deletion types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ type MiddlewareOf[T any] interface {
// method 当前路由的请求方法;
// pattern 当前路由的匹配项;
//
// 对于不存在的路由项,method 和 pattern 都为空。
// NOTE: method 和 pattern 在某些特殊的路由项中会有特殊的值:
// - 404 method 和 pattern 均为空;
// - 405 method 为空,pattern 正常;
Middleware(next T, method, pattern string) T
}

Expand Down

0 comments on commit 1b632f6

Please sign in to comment.