xgfone / ship

A flexible, powerful, high performance and minimalist Go Web HTTP router framework.
https://github.com/xgfone/ship
Apache License 2.0
48 stars 5 forks source link

添加 path 相同且带有 Name 的路由会 panic #12

Closed xmx closed 1 year ago

xmx commented 2 years ago
package main

import (
    "net/http"

    "github.com/xgfone/ship/v5"
)

func main() {
    handler := ship.OkHandler()

    s := ship.New()
    s.Route("/user").Name("添加用户").Method(handler, http.MethodPost)
    s.Route("/user").Name("删除用户").Method(handler, http.MethodDelete)
    // panic: inconsistent route name: name=删除用户, path=/user, method=DELETE
}

复现代码如上所述。

比如在业务中,POST /user添加用户 逻辑,DELETE /user删除用户 逻辑,

在注册路由时候业务名称设置成路由的名字,就会 panic,查看源码发现是 Router.Add 做了校验。

虽然可以使用 Route.Data 解决上述问题,但是还是有点疑惑:

为什么路由的 namepath 唯一对应,而不是 namemethod + path 唯一对应?

xgfone commented 2 years ago

name 并不是用来唯一命名一个路由的,它是用来命名 path 的。设计它的目的是为了通过 名字+参数 引用并反射出相应的 URL PATH 路径。比如:我们注册了下面的路由Route:

router := ship.New()
router.Route("/path/:arg1/to/:arg2").Name("name").Method(handler, http.MethodGET)

当你在写服务器端HTML渲染的Web页面时,如果 Web 中要使用这个路径(根据不同的参数,生成不同的 URL),可以这样使用

url := router. Router.Path("name", "value1", "value2") // => "/path/value1/to/value2"

然后把 url 变量在 HTML 模板中使用。当然,也可以把 Router.Path 这个函数变成一个模板函数(假设模板函数为 URLPath),这样就可以直接在模板中动态生成不同的 URL 了,如:URLPath 1 2 就成渲染出 /path/1/to/2

另外,name 仅对 Path() 有用,不影响 Router 的核心功能(即,通过 Path+Method 进行路由不同的请求给不同的处理器),所以最终添加、删除、匹配路由,还是由 Path 来起核心决定(而非 name)。为了避免不一致造成的未知问题,默认的 Router 实现在注册路由时要求,如果 path 相同,对应的 name 也要相同,否则就会 panic

所以,对于上面的路由,注册时,name 需要一致,如下:

package main

import (
    "net/http"

    "github.com/xgfone/ship/v5"
)

func main() {
    handler := ship.OkHandler()

    s := ship.New()
    s.Route("/user").Name("用户").Method(handler, http.MethodPost)
    s.Route("/user").Name("用户").Method(handler, http.MethodDelete)
}
xmx commented 2 years ago

好的,了解了