mux 是对 http.ServeMux 的扩展,添加正则路由等功能。
- 路由参数;
- 支持正则表达式作为路由项匹配方式;
- 拦截正则表达式的行为;
- 自动生成 OPTIONS 请求处理方式;
- 自动生成 HEAD 请求处理方式;
- 根据路由反向生成地址;
- 任意风格的路由,比如 discuz 这种不以 / 作为分隔符的;
- 分组路由,比如按域名,或是版本号等;
- CORS 跨域资源的处理;
- 支持中间件;
- 自动生成 OPTIONS * 请求;
- 静态文件系统;
import "github.com/issue9/middleware/v4/compress" import "github.com/issue9/mux/v5" c := compress.New() router := mux.NewRouter("") router.Middlewares().Append(c) router.Get("/users/1", h). Post("/login", h). Get("/pages/{id:\\d+}.html", h). // 匹配 /pages/123.html 等格式,path = 123 Get("/posts/{path}.html", h). // 匹配 /posts/2020/11/11/title.html 等格式,path = 2020/11/11/title // 统一前缀路径的路由 p := router.Prefix("/api") p.Get("/logout", h) // 相当于 m.Get("/api/logout", h) p.Post("/login", h) // 相当于 m.Get("/api/login", h) // 对同一资源的不同操作 res := p.Resource("/users/{id:\\d+}") res.Get(h) // 相当于 m.Get("/api/users/{id:\\d+}", h) res.Post(h) // 相当于 m.Post("/api/users/{id:\\d+}", h) res.URL(map[string]string{"id": "5"}) // 构建一条基于此路由项的路径:/users/5 http.ListenAndServe(":8080", router)
路由参数采用大括号包含,内部包含名称和规则两部分:`{name:rule}`, 其中的 name 表示参数的名称,rule 表示对参数的约束规则。 name 可以包含 `-` 前缀,表示在实际执行过程中,不捕获该名称的对应的值, 可以在一定程序上提升性能。 rule 表示对参数的约束,一般为正则或是空,为空表示匹配任意值, 拦截器一栏中有关 rule 的高级用法。以下是一些常见的示例。 ```text /posts/{id}.html // 匹配 /posts/1.html /posts-{id}-{page}.html // 匹配 /posts-1-10.html /posts/{path:\\w+}.html // 匹配 /posts/2020/11/11/title.html /tags/{tag:\\w+}/{path} // 匹配 /tags/abc/title.html ``` ### 路径匹配规则 可能会出现多条记录与同一请求都匹配的情况,这种情况下, 系统会找到一条认为最匹配的路由来处理,判断规则如下: 1. 普通路由优先于正则路由; 1. 拦截器优先于正则路由; 1. 正则路由优先于命名路由; 比如: ```text /posts/{id}.html // 1 /posts/{id:\\d+}.html // 2 /posts/1.html // 3 /posts/1.html // 匹配 3 /posts/11.html // 匹配 2 /posts/index.html // 匹配 1 ``` 路径的匹配是以从左到右的顺序进行的,父节点不会因为没有子节点匹配而扩大自己的匹配范围, 比如 `/posts/{id}-{page:digit}.html` 可以匹配 `/posts/1-1.html`,但无法匹配 `/posts/1-1-1.html`,虽然理论上 `1-1-` 也能匹配 `{id}`,但是 `1-` 已经优先匹配了, 在子元素找不到的情况下,并不会将父元素的匹配范围扩大到 `1-1-`。 ### 路由参数 通过正则表达式匹配的路由,其中带命名的参数可通过 `GetParams()` 获取: ```go import "github.com/issue9/mux/v5" params := mux.GetParams(r) id, err := params.Int("id") // 或是 id := params.MustInt("id", 0) // 在无法获取 id 参数时采用 0 作为默认值返回 ``` ## 高级用法 ### 分组路由 可以通过匹配 `group.Matcher` 接口,定义了一组特定要求的路由项。 ```go // server.go import "github.com/issue9/mux/v5" import "github.com/issue9/mux/v5/group" m := group.New() def := mux.NewRouter("default", false, nil) m.AddRouter(group.NewPathVersion("version-key", "v1"), def) def.Get("/path", h1) host := mux.NewRouter("host", false, nil) m.AddRouter(group.NewHosts("*.example.com"), host) host.Get("/path", h2) http.ListenAndServe(":8080", m) // client.go // 访问 h2 的内容 r := http.NewRequest(http.MethodGet, "https://abc.example.com/path", nil) r.Do() // 访问 h1 的内容 r := http.NewRequest(http.MethodGet, "https://other_domain.com/v1/path", nil) r.Do() ``` ### 拦截器 正常情况下,`/posts/{id:\d+}` 或是 `/posts/{id:[0-9]+}` 会被当作正则表达式处理, 但是正则表达式的性能并不是很好,这个时候我们可以通过在 `NewRouter` 传递 `Interceptor` 进行拦截: ```go import "github.com/issue9/mux/v5" func digit(path string) bool { for _, c := range path { if c < '0' || c > '9' { return false } } return len(path) > 0 } // 路由中的 \d+ 和 [0-9]+ 均采用 digit 函数进行处理,不再是正则表达式。 r := mux.NewRouter("", mux.Interceptor(digit, "\\d+", "[0-9]+")) ``` 这样在所有路由项中的 `[0-9]+` 和 `\\d+` 将由 `digit` 函数处理, 不再会被编译为正则表达式,在性能上会有很大的提升。 通过该功能,也可以自定义一些非正常的正则表达这式,然后进行拦截,比如: ```text /posts/{id:digit}/.html ``` 如果不拦截,最终传递给正则表达式,可能会出现编译错误,通过拦截器可以将 digit 合法化。 目前提供了以下几个拦截器: - InterceptorDigit 限定为数字字符,相当于正则的 `[0-9]`; - InterceptorWord 相当于正则的 `[a-zA-Z0-9]`; - InterceptorAny 表示匹配任意非空内容; 用户也可以自行实现 `InterceptorFunc` 作为拦截器。具体可参考 <https://pkg.go.dev/github.com/issue9/mux/v5#Interceptor> ### CORS CORS 不再是以中间件的形式提供,而是通过 NewRouter 直接传递有关 CORS 的配置信息, 这样可以更好地处理每个地址支持的请求方法。 OPTIONS 请求方法由系统自动生成。 ```go import "github.com/issue9/mux/v5" r := mux.NewRouter("name" ,AllowedCORS) // 任意跨域请求 r.Get("/posts/{id}", nil) // 默认情况下, OPTIONS 的报头为 GET, OPTIONS http.ListenAndServe(":8080", m) // client.go // 访问 h2 的内容 r := http.NewRequest(http.MethodGet, "https://localhost:8080/posts/1", nil) r.Header.Set("Origin", "https://example.com") r.Do() // 跨域,可以正常访问 r = http.NewRequest(http.MethodOptions, "https://localhost:8080/posts/1", nil) r.Header.Set("Origin", "https://example.com") r.Header.Set("Access-Control-Request-Method", "GET") r.Do() // 预检请求,可以正常访问 ``` ### 静态文件 可以使用 `FileServer` 与命名参数相结合的方式实现静态文件的访问: ```go r := NewRouter("") r.Get("/assets/{path}", FileServer(os.DirFS("/static/"), "path", "index.html", nil)) ``` ### 中间件 mux 本身就是一个实现了 [http.Handler](https://pkg.go.dev/net/http#Handler) 接口的中间件, 所有实现官方接口 `http.Handler` 的都可以附加到 mux 上作为中间件使用。 mux 本身也提供了对中间件的管理功能,同时 [middleware](https://github.com/issue9/middleware) 提供了常用的中间件功能。 ```go import "github.com/issue9/middleware/v4/compress" c := compress.New(log.Default(), "*") r := mux.NewRouter("") // 添加中间件 r.Middlewares().Append(c.Middleware) ```
## 性能
<https://caixw.github.io/go-http-routers-testing/> 提供了与其它几个框架的对比情况。
PXA1802使用HSIC接口与AP连接,HSIC枚举实现7个虚拟通道ttyUSB0~6,为方便扩展,Marvell在HSIC虚拟通道0上实现了3GPP GSM-07.10 MUX协议,MUX协议提供多路数据流复用底层单一通道,多路数据流互不干扰的多路复用方法。MUX通道主要用于AT命令,通话音量控制,NVM操作等小数据量的通讯,网络PS业务和CP调试LOG都直接使用HSIC虚拟通道。本文主要介绍
转载:《ASIC 中时钟 MUX 电路结构时序约束的方法分析》论文 MUX 前无逻辑的时钟结构 数字电路从时钟来源上可分为同步电路和异步电路。一个大型设计中所有逻辑很难全部是同步的,异步设计不可避免。并且,部分设计需要在不同情况下工作在不同频率,尤其在通信芯片中,由于场景多样,不仅有频率的变化,还有时钟的切换。这就需要在时钟来源上加入 MUX 器件,用来进行时钟切换。从而形成了图 1 所示的时钟结
module mux_pro #( parameter D = 4, parameter W = 6 ) ( input wire [D*W-1:0] i_array, input wire [D-1:0] i_hot, output reg [W-1:0] o_sel ); always @(*) begin :proc_dmux in
github地址: https://github.com/gorilla/mux#matching-routes https://gitee.com/mirrors/mux#examples http://www.gorillatoolkit.org/pkg/mux https://github.com/gorilla/mux#examples 代码示例: import ( "encoding/
问题内容: https://cloud.google.com/appengine/docs/go/users/ 我在这里看到他们没有指定使用任何路由器…:https : //cloud.google.com/appengine/docs/go/config/appconfig 在与Golang一起使用的Google Cloud中,它表示要在中指定每个处理程序。这是否意味着我们不应该使用第三方路由器
路由功能浅谈 在本章 选择恰当的分片数量和分片副本数量 一节中,已经提到使用路由功能可以只在一个分片上执行查询命令,作为提高系统吞吐量的一种解决方案。接下来作者将详细地介绍这一功能。 分片和分片中数据 通常情况下,ElasticSearch是如何把数据分发到各个分片中,哪个分片存储哪一类的文档等细节并不重要。因为查询时,将查询命令分发到每个分片就OK了。唯一的关键点在于算法,将数据均等地分配到各个
我想创建OpenAPI UI规范,在静态编程语言上使用Spring WebFlux功能路由器。Spring Boot v.2.5.2,springdoc-openapi v.1.5.9。这是我的路由器类: 我想创建一个 GET 查询,如 其中1是我想要的用户ID。 但我的OpenAPI的UI仍然尝试使用GET参数创建查询 这显然会导致错误400。很高兴知道我的@RouterAction应该如何正确
本文向大家介绍JS实现简单路由器功能的方法,包括了JS实现简单路由器功能的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JS实现简单路由器功能的方法。分享给大家供大家参考。具体实现方法如下: 希望本文所述对大家的javascript程序设计有所帮助。
我是否可以使用新的Kotlin DSL设置路由,例如: 是否使用非反应web部件?因为底层数据库将是Postgres和非反应性的基于servlet的应用服务器,所以我不想/不需要使用Flux或Mono来返回类型或存储库函数。但我喜欢新的路由器DSL与Kotlin一起使用,它比基于注释的功能更强大,更容易掌握所有的应用程序路由。
本文向大家介绍Django DRF路由与扩展功能的实现,包括了Django DRF路由与扩展功能的实现的使用技巧和注意事项,需要的朋友参考一下 一. 视图集与路由的使用 使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中: list() 提供一组数据 retrieve() 提供单个数据 create() 创建数据 update() 保存数据 destory() 删除数据 ViewSe
问题内容: 我对Go来说还很陌生,还无法找到任何有关此的信息,也许目前尚无法解决。 我正在尝试删除或替换多路复用器路由(使用http.NewServeMux或大猩猩的mux.Router)。我的最终目标是能够启用/禁用一条路由或一组路由,而不必重新启动程序。 我可能可以在处理程序到处理程序的基础上完成此操作,并且如果该功能被“禁用”,则只返回404,但是我宁愿找到一种更通用的方法来执行此操作,因为
问题内容: 情况: 我想从控制台获取密码输入- 而不回显用户键入的内容 。有什么可以和Go中的功能媲美吗? 我试过的 我尝试使用,但它回显了键入的内容。 问题答案: 您可以通过执行以下操作来关闭回显,然后在读取密码后将其重新打开