帮酷LOGO
  • 显示原文与译文双语对照的内容
xmux is a httprouter fork on top of xhandler (net/context aware)

  • 源代码名称:xmux
  • 源代码网址:http://www.github.com/rs/xmux
  • xmux源代码文档
  • xmux源代码下载
  • Git URL:
    git://www.github.com/rs/xmux.git
  • Git Clone代码到本地:
    git clone http://www.github.com/rs/xmux
  • Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/rs/xmux
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
  • Xmux

    godoclicenseBuild StatusCoverage

    Xmux是一个轻量级的高性能HTTP请求 muxer,位于 xhandler服务器上。 Xmux从令人惊奇的httprouter的fork 获得它的速度。 路由参数存储在 context 中而不是作为附加参数传递。

    缺省的go包的默认复用器相比,这个支持路由 Pattern 中的变量,并针对请求方法支持 MATCHES 。 它也能更好地。

    muxer针对高性能和内存占用进行了优化。 即使很长的路径和大量的路线,它也会扩展。 一种压缩动态 trie ( radix ) 结构的有效匹配。

    特性

    只有显式匹配:与其他 muxers,如 http.ServeMux,请求的URL路径可以在多个模式。 因此,他们有一些笨拙的Pattern 优先规则,比如最长匹配或者第一次注册,第一次匹配的。 通过设计这个路由器,请求只能 MATCH 一个或者无路由。 因这里,也没有意外的MATCHES,这使得它对SEO很好,提高了用户体验。

    停止关注跟踪斜线: 如果你想要的是URL样式,那么如果缺少尾部斜杠或者有一个额外的地址,那么会自动重定向客户端。 当然,如果新路径有一个处理程序,那么它只是这样。 如果你不喜欢,你可以关闭这里行为的关闭。

    自动调整路径自动更正:除了检测丢失或者额外的尾部斜杠外,还可以修复错误,并可以修复错误的情况并删除多余的路径元素。 船长 CAPS LOCK 你的一个用户? Xmux可以帮助他不区分大小写的查找,并将它的重定向到正确的URL 。

    你的路由 Pattern 中有参数: 停止解析请求的URL路径,只给路径段一个 NAME,路由器将动态值传递给你。 由于路由器的设计,路径参数非常便宜。

    RouteGroups: 一种创建路由组的方法,无需任何请求开销即可创建路由组。

    零垃圾: 匹配和调度进程生成零字节的垃圾。 实际上,所做的唯一堆分配是通过构建路径参数的key-value 对和 context 实例来存储上下文。 如果请求路径不包含任何参数,则不需要单个堆分配。

    没有更多服务器崩溃: 你可以设置一个应急处理程序处理处理HTTP请求期间发生的恐慌。 路由器然后恢复并让 PanicHandler 记录发生的事情,并提供一个好的错误页面。

    当然,你还可以设置定制的MethodNotAllowed处理程序 。

    用法

    这只是一个简单的介绍,查看 GoDoc的细节。

    让我们从一个简单的例子开始:

    package mainimport (
     "fmt""log""net/http""context""github.com/rs/xhandler""github.com/rs/xmux")funcIndex(ctxcontext.Context, whttp.ResponseWriter, r *http.Request) {
     fmt.Fprint(w, "Welcome!n")
    }funcHello(ctxcontext.Context, whttp.ResponseWriter, r *http.Request) {
     fmt.Fprintf(w, "hello, %s!n", xmux.Param(ctx, "name"))
    }funcmain() {
     mux:= xmux.New()
     mux.GET("/", xhandler.HandlerFuncC(Index))
     mux.GET("/hello/:name", xhandler.HandlerFuncC(Hello))
     log.Fatal(http.ListenAndServe(":8080", xhandler.New(context.Background(), mux)))
    }

    你还可以使用 xhandler.Chain 来链接中间件:

    package mainimport (
     "context""fmt""log""net/http""time""github.com/rs/xhandler""github.com/rs/xmux")funcmain() {
     c:= xhandler.Chain{}
     // Append a context-aware middleware handler c.UseC(xhandler.CloseHandler)
     // Another context-aware middleware handler c.UseC(xhandler.TimeoutHandler(2 * time.Second))
     mux:= xmux.New()
     // Use c.Handler to terminate the chain with your final handler mux.GET("/welcome/:name", xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
     fmt.Fprintf(w, "Welcome %s!", xmux.Param(ctx, "name"))
     }))
     iferr:= http.ListenAndServe(":8080", c.Handler(mux)); err!= nil {
     log.Fatal(err)
     }
    }

    命名参数

    如你所见,:name 是一个名为的参数。 这些值可以通过 xmux.Params(ctx) 访问,后者返回 xmux.ParamHolder 。 你可以使用 Get(name) 方法通过它的NAME 获取参数的值:

    user:= xmux.Params(ctx).Get("user")

    或者使用 xmux.Param(ctx, name) 快捷键:

    user:= xmux.Param(ctx, "user")

    命名参数仅用于单个路径段:

    Pattern:/user/:user
    /user/gordon match
    /user/you match
    /user/gordon/profile no match
    /user/no match

    注意:因为这个muxer只有显式的MATCHES,所以你不能为同一路径段选择 static 路由和参数。 例如,不能同时为同一请求方法 register 和 /user/:user的模式 /user/new 和。 不同请求方法的路由彼此独立。

    捕获所有参数

    第二种类型是 ,捕获所有的参数并具有 *name 格式。 就像 NAME 建议的那样他们把所有的东西。 因此,它们必须始终在的:

    Pattern:/src/*filepath
    /src/match
    /src/somefile.go match
    /src/subdir/somefile.go match

    基准测试

    多亏了的优秀HTTP路由基准,我们可以看到xhandler的muxer非常接近 httprouter,因为它是其中的一个 fork 。 小开销是由于用于存储路由参数的context 分配所造成的。 它仍然优于其他路由器,多亏了令人惊奇的httprouter 基匹配器。

    BenchmarkXhandler_APIStatic-8 50000000 39.6 ns/op 0 B/op 0 allocs/op
    BenchmarkChi_APIStatic-8 3000000 439 ns/op 144 B/op 5 allocs/op
    BenchmarkGoji_APIStatic-8 5000000 272 ns/op 0 B/op 0 allocs/op
    BenchmarkHTTPRouter_APIStatic-8 50000000 37.3 ns/op 0 B/op 0 allocs/op
    BenchmarkXhandler_APIParam-8 5000000 328 ns/op 160 B/op 4 allocs/op
    BenchmarkChi_APIParam-8 2000000 675 ns/op 432 B/op 6 allocs/op
    BenchmarkGoji_APIParam-8 2000000 692 ns/op 336 B/op 2 allocs/op
    BenchmarkHTTPRouter_APIParam-8 10000000 166 ns/op 64 B/op 1 allocs/op
    BenchmarkXhandler_API2Params-8 5000000 362 ns/op 160 B/op 4 allocs/op
    BenchmarkChi_API2Params-8 2000000 814 ns/op 432 B/op 6 allocs/op
    BenchmarkGoji_API2Params-8 2000000 680 ns/op 336 B/op 2 allocs/op
    BenchmarkHTTPRouter_API2Params-8 10000000 183 ns/op 64 B/op 1 allocs/op
    BenchmarkXhandler_APIAll-8 200000 6473 ns/op 2176 B/op 64 allocs/op
    BenchmarkChi_APIAll-8 100000 17261 ns/op 8352 B/op 146 allocs/op
    BenchmarkGoji_APIAll-8 100000 15052 ns/op 5377 B/op 32 allocs/op
    BenchmarkHTTPRouter_APIAll-8 500000 3716 ns/op 640 B/op 16 allocs/op
    BenchmarkXhandler_Param1-8 5000000 271 ns/op 128 B/op 4 allocs/op
    BenchmarkChi_Param1-8 2000000 620 ns/op 432 B/op 6 allocs/op
    BenchmarkGoji_Param1-8 3000000 522 ns/op 336 B/op 2 allocs/op
    BenchmarkHTTPRouter_Param1-8 20000000 112 ns/op 32 B/op 1 allocs/op
    BenchmarkXhandler_Param5-8 3000000 414 ns/op 256 B/op 4 allocs/op
    BenchmarkChi_Param5-8 1000000 1204 ns/op 432 B/op 6 allocs/op
    BenchmarkGoji_Param5-8 2000000 847 ns/op 336 B/op 2 allocs/op
    BenchmarkHTTPRouter_Param5-8 5000000 247 ns/op 160 B/op 1 allocs/op
    BenchmarkXhandler_Param20-8 2000000 747 ns/op 736 B/op 4 allocs/op
    BenchmarkChi_Param20-8 2000000 746 ns/op 736 B/op 4 allocs/op
    BenchmarkGoji_Param20-8 500000 2439 ns/op 1247 B/op 2 allocs/op
    BenchmarkHTTPRouter_Param20-8 3000000 585 ns/op 640 B/op 1 allocs/op
    BenchmarkXhandler_ParamWrite-8 5000000 404 ns/op 144 B/op 5 allocs/op
    BenchmarkChi_ParamWrite-8 3000000 407 ns/op 144 B/op 5 allocs/op
    BenchmarkGoji_ParamWrite-8 2000000 594 ns/op 336 B/op 2 allocs/op
    BenchmarkHTTPRouter_ParamWrite-8 10000000 166 ns/op 32 B/op 1 allocs/op

    你可以通过在 xmux 存储库的root 中执行以下命令来运行这里基准:

    go get -t./bench/routersgo test./bench/routers -bench. 

    :它是如何工作的

    muxer依赖树结构,大量使用常用前缀,它基本上是一个 compact 前缀树 ( 或者只是 。) 。 具有公共前缀的节点也共享公共父节点。 下面是 GET 请求方法的路由树可能看起来像的一个简短示例:

    Priority Path Handle
    9 *<1>
    3 ├s nil
    2 |├earch *<2>
    1 |└upport *<3>
    2 ├blog *<4>
    1 | └:post nil
    1 | └ *<5>
    2 ├about-us *<6>
    1 | └team *<7>
    1 └contact *<8>

    每个 *<num> 代表处理器函数( 指针)的内存地址。 在树的树中,如果沿着路径槽,则得到完整的路径路径,即 比如,其中 :post 只是实际 post NAME的占位符( 。参数 ) 。 哈希映射不同,树结构也允许我们使用像 :post 参数这样的动态部分,因为我们对路由模式进行了 MATCH 比较。 作为基准显示,这是非常有效和有效的。

    因为URL路径具有层次结构并且仅使用一组有限的字符( 字节值),所以很可以能有很多共同前缀。 这使得我们可以轻松地将路由减少到更小的问题。 此外,路由器为每个请求方法管理一个单独的树。 比如,在每一个页面中都有一个 method-> 句柄映射,在前缀树中开始查找之前,这还允许我们大大减少路由问题。

    为了获得更好的可伸缩性,树级别的子节点按优先级排序,优先级只是在子节点( 子对象,子对象等等。) 中注册的句柄的数量。 这有两种帮助:

    • 作为大多数路由路径的一部分的节点首先进行计算。 这有助于使尽可能多的线路达到尽可能快的速度。
    • 是某种成本补偿。 最长的可以到达路径( 最高成本) 总是可以被。 下面的方案可视化树结构。 从上到下和从左到右计算节点。
    ├------------
    ├---------
    ├-----
    ├----
    ├--
    ├--
    └-

    为什么这与 http.Handler 不适用?

    英镑 路由器本身实现 http.Handler 接口。 路由器为 http.Handler 和 http.HandlerFunc 提供了方便的适配器,在注册路由器时,它可以作为xhandler.HandlerC 。 唯一的缺点是,当使用 http.Handler 或者 http.HandlerFunc 时,不能检索任何 context,因此不能检索参数值。

    我可以在哪里找到中间件 X

    这个软件包提供了一个非常高效的请求 muxer,并提供了一些额外的特性。 muxer只是 xhandler.HandlerC 插件,你可以在路由器之前链任何 http.Handler 或者 xhandler.HandlerC 兼容中间件,例如大猩猩处理程序( ) 。 或者你也可以自己写,很容易 !

    域/子域

    下面是一个简单的例子: 你的服务器是否服务多个域/主机? 你想使用子域? 为每个主机定义路由器 !

    // We need an object that implements the xhandler.HandlerC interface.// Therefore we need a type for which we implement the ServeHTTP method.// We just use a map here, in which we map host names (with port) to xhandler.HandlerCtypeHostSwitchmap[string]xhandler.HandlerC// Implement the ServerHTTP method on our new typefunc(hsHostSwitch) ServeHTTPC(ctxcontext.Context, whttp.ResponseWriter, r *http.Request) {
     // Check if a xhandler.HandlerC is registered for the given host.// If yes, use it to handle the request.ifhandler:= hs[r.Host]; handler!= nil {
     handler.ServeHTTPC(ctx, w, r)
     } else {
     // Handle host names for wich no handler is registered http.Error(w, "Forbidden", 403) // Or Redirect? }
    }funcmain() {
     c:= xhandler.Chain{}
     // Initialize a muxer as usualmux:= xmux.New()
     mux.GET("/", Index)
     mux.GET("/hello/:name", Hello)
     // Make a new HostSwitch and insert the muxer (our http handler)// for example.com and port 12345hs:=make(HostSwitch)
     hs["example.com:12345"] = mux
     // Use the HostSwitch to listen and serve on port 12345iferr:= http.ListenAndServe(":12345", c.Handler(hs)); err!= nil {
     log.Fatal(err)
     }
    }

    基本身份验证

    另一个快速示例:句柄的基本身份验证( RFC 2617 ):

    package mainimport (
     "bytes""context""encoding/base64""fmt""log""net/http""strings""github.com/rs/xhandler""github.com/rs/xmux")funcBasicAuth(user, pass []byte, nextxhandler.HandlerC) xhandler.HandlerC {
     return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
     const basicAuthPrefix string = "Basic "// Get the Basic Authentication credentialsauth:= r.Header.Get("Authorization")
     if strings.HasPrefix(auth, basicAuthPrefix) {
     // Check credentialspayload, err:= base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
     if err == nil {
     pair:= bytes.SplitN(payload, []byte(":"), 2)
     iflen(pair) == 2 &&
     bytes.Equal(pair[0], user) &&
     bytes.Equal(pair[1], pass) {
     // Delegate request to the next handler next.ServeHTTPC(ctx, w, r)
     return }
     }
     }
     // Request Basic Authentication otherwise w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
     http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
     })
    }funcIndex(ctxcontext.Context, whttp.ResponseWriter, r *http.Request) {
     fmt.Fprint(w, "Not protected!n")
    }funcProtected(ctxcontext.Context, whttp.ResponseWriter, r *http.Request) {
     fmt.Fprint(w, "Protected!n")
    }funcmain() {
     user:= []byte("gordon")
     pass:= []byte("secret!")
     c:= xhandler.Chain{}
     mux:= xmux.New()
     mux.GET("/", xhandler.HandlerFuncC(Index))
     mux.GET("/protected/", BasicAuth(user, pass, xhandler.HandlerFuncC(Protected)))
     log.Fatal(http.ListenAndServe(":8080", c.Handler(mux)))
    }

    许可证

    所有源代码都是 BSD许可协议下的许可证。

    Xmux是来自 httprouter的fork,带有 BSD许可证。




    Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语