erouter
Erouter is a high performance and high scale HTTP routing library with zero memory replication, strict routing order, low code complexity, group routing, middleware functionality, default parameters, constant matching, variable matching, wildcard matching, variable verification matching, wildcard verification matching, and host-based routing.
Design specification
Based on eudore framework routing separation, middleware mechanism was modified and MVC was removed.
RouterRadix
RouterRadix is implemented using cardinality tree, with zero memory replication, strict routing matching order, group routing, middleware functions, default parameters, constant matching, variable matching, wildcard matching functions.
example:
package main
import "log"
import "net/http"
import "github.com/eudore/erouter"
func main(a) {
router := erouter.NewRouterRadix()
router.AddMiddleware("ANY"."".func(h erouter.Handler) erouter.Handler {
return func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
log.Printf("%s %s route: %s", r.Method, r.URL.Path, p.GetParam("route"))
h(w, r, p)
}
})
router.Any("/ *".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("hello\n"))
})
router.Get("/api/*action version=v0".func(w http.ResponseWriter, _ *http.Request, p erouter.Params) {
w.Write([]byte("access api " + p.GetParam("version") +":" + p.GetParam("action") + "\n"))
})
router.Get("/api/v1/*action version=v1".func(w http.ResponseWriter, _ *http.Request, p erouter.Params) {
w.Write([]byte("access api " + p.GetParam("version") +":" + p.GetParam("action") + "\n"))
})
apiv2 := router.Group("/api/v2 version=v2")
apiv2.Any("/*action".func(w http.ResponseWriter, _ *http.Request, p erouter.Params) {
w.Write([]byte("access api " + p.GetParam("version") +":" + p.GetParam("action") + "\n"))
})
http.ListenAndServe(": 8080", router)
}
Copy the code
Test command:
The curl 127.0.0.1:8080 / get curl 127.0.0.1:8080 / API/getuser curl 127.0.0.1:8080 / API/v1 / getuser curl 127.0.0.1:8080 / API/v2 / getuserCopy the code
RouterFull
RouterFull is based on the RouterRadix extension to implement variable check matching and wildcard check matching functions.
Usage: after the normal variable and a wildcard, use ‘|’ symbol segmentation, for after checking rules, isnum is check function; Min :100 is the dynamic check function, min is the name of the dynamic check function, and ‘:’ is the parameter. If ‘^’ begins with the regular check and ends with ‘$’.
Note: Do not use Spaces in regular expressions, as this can lead to error parameter cutting. Use \u002 instead of Spaces.
:num|isnum
:num|min:100
:num|^0.*$
*num|isnum
*num|min:100
*num|^0.*$
Copy the code
example:
package main
import "net/http"
import "github.com/eudore/erouter"
func main(a) {
router := erouter.NewRouterFull()
router.Any("/ *".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("hello\n"))
})
router.Get("/:num|^0.*$".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("first char is '0', num is: " + p.GetParam("num") + "\n"))
})
router.Get("/:num|min:100".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("num great 100, num is: " + p.GetParam("num") + "\n"))
})
router.Get("/:num|isnum".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("num is: " + p.GetParam("num") + "\n"))
})
router.Get("/*var|^E.*$".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("first char is 'E', var is: " + p.GetParam("var") + "\n"))
})
http.ListenAndServe(": 8080", router)
}
Copy the code
Test command:
Do you want to use the following curl to do something: 1 127.0.0.1:8080 / Erouter / 123Copy the code
RouterHost
RouterHost implements host-based routing by registering and matching sub-routers corresponding to hosts.
Currently, traversal matches are used, and the Host matching function is path.Match. In the future, only ‘*’ wildcards and constants are reserved for matching rules.
Usage: To register a sub-router under the rule of domain name registration for the Host router, add a route using the Host parameter to match the registered router, and use the requested Host to match the registered route.
example:
package main
import "net/http"
import "github.com/eudore/erouter"
func main(a) {
router := erouter.NewRouterHost().(*erouter.RouterHost)
router.RegisterHost("*.example.com", erouter.NewRouterRadix())
router.Any("/ *".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("hello\n"))
})
router.Get("/* host=*.example.com".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
w.Write([]byte("host is " + r.Host + ", match host: " + p.GetParam("host") + "\n"))
})
http.ListenAndServe(": 8080", router)
}
Copy the code
Test command:
Curl 127.0.0.1:8080 curl -xput 127.0.0.1:8080 curl -h'Host: www.example.com'127.0.0.1: curl - 8080 H'Host: www.example.com'The curl - H - XPUT 127.0.0.1:8080'Host: www.example.com'- Xput 127.0.0.1:8080Copy the code
Benchmark
Using GithubApi, Erouter achieves 60% of httprOUTER’s matching performance, but has strict route matching sequence, easy to extend and rewrite, and low code complexity.
Test command:
go get github.com/eudore/web-framework-benchmark
go test -bench=router github.com/eudore/web-framework-benchmark
Copy the code
Test results:
goos: linux goarch: amd64 pkg: github.com/eudore/web-framework-benchmark BenchmarkHttprouterStatic-2 50000 25518 ns/op 1949 B/op 157 allocs/op BenchmarkHttprouterGitHubAPI-2 30000 57961 ns/op 16571 B/op 370 allocs/op BenchmarkHttprouterGplusAPI-2 500000 2747 ns/op 813 B/op 24 allocs/op BenchmarkHttprouterParseAPI-2 300000 3886 ns/op 963 B/op 42 allocs/op BenchmarkErouterRadixStatic-2 30000 44147 ns/op 2412 B/op 157 allocs/op BenchmarkErouterRadixGitHubAPI-2 20000 63756 ns/op 2501 B/op 203 allocs/op BenchmarkErouterRadixGplusAPI-2 500000 2653 ns/op 173 B/op 13 allocs/op BenchmarkErouterRadixParseAPI-2 300000 4523 ns/op 323 B/op 26 allocs/op BenchmarkErouterFullStatic-2 30000 43923 ns/op 2413 B/op 157 allocs/op BenchmarkErouterFullGitHubAPI-2 20000 65698 ns/op 2503 B/op 203 allocs/op BenchmarkErouterFullGplusAPI-2 500000 2582 ns/op 173 B/op 13 allocs/op BenchmarkErouterFullParseAPI-2 300000 5990 ns/op 323 B/ OP 26 Allocs/OP PASS OK github.com/eudore/web-framework-benchmark 19.934sCopy the code
Api
The main methods used are listed in the reference documentation.
Router interface definition:
type (
// Params read/write request processing parameters.
Params interface {
GetParam(string) string
AddParam(string.string)
SetParam(string.string)}// Erouter handles a request method, adding Parmas to http.handlerfunc.
Handler func(http.ResponseWriter, *http.Request, Params)// Define a request processing middleware function that uses decorator assembly to process the request by passing in a processing and then returning a processing.Middleware func(Handler) Handler
// The route is directly registered by default. Other methods can be directly registered using the RouterRegister interface// // Routes are directly registered by default. Other routes can be registered by defaultRouterRegisterInterface direct registration.RouterMethod interface {
Group(string) RouterMethod
AddHandler(string.string, Handler) RouterMethod
AddMiddleware(string.string. Middleware) RouterMethod NotFound(Handler) MethodNotAllowed(Handler) Any(string, Handler)
Delete(string, Handler)
Get(string, Handler)
Head(string, Handler)
Options(string, Handler)
Patch(string, Handler)
Post(string, Handler)
Put(string, Handler)
}
// Router core interface, performing routing, middleware registration, and processing http requests.
//
// The router core interface performs routing, middleware registration, and processing HTTP requests.
RouterCore interface {
RegisterMiddleware(string.string, []Middleware)
RegisterHandler(string.string, Handler)
ServeHTTP(http.ResponseWriter, *http.Request)
}
// The router interface needs to implement two methods: the router method and the router core.
//
// Implement router method and router core interfaces.
Router interface {
RouterCore
RouterMethod
}
)
Copy the code
NewRouter
There are currently three implementations, each of which implements the Router interface.
func NewRouterRadix() Router
func NewRouterFull() Router
func NewRouterHost() Router
Copy the code
router1 := erouter.NewRouterRadix()
router2 := erouter.NewRouterFull()
router3 := erouter.NewRouterHost()
Copy the code
Group
func Group(path string) RouterMethod
Group Implements router grouping.
router := erouter.NewRouterRadix()
apiv1 := router.Group("/api/v1 version=v1")
apiv1.Get("/ *",...).Copy the code
AddHandler
func AddHandler(method string, path string, handler Handler) RouterMethod
AddHandler is used to add a new route.
router := erouter.NewRouterRadix()
router.AddHandle("GET"."/ *",...).Copy the code
AddMiddleware
func AddMiddleware(method string, path string, midds ... Middleware) RouterMethod
AddMiddleware adds processing middleware to the current routing method.
router := erouter.NewRouterRadix()
router.AddMiddleware("ANY"."".func(h erouter.Handler) erouter.Handler {
return func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
/ / befor.// Call next to handle the summary function
h(w, r, p)
/ / after execution. }})Copy the code
NotFound
func NotFound(Handler)
Set up router 404 processing.
MethodNotAllowed
func MethodNotAllowed(Handler)
Set router 405 processing.
Any
func Any(path string, handler Handler)
Register the Any method, equivalent to AddHandler’s method “Any”.
The set of Any methods is erouter.RouterAllMethod. The extended new methods Radix and Full are not supported.
Get
func Get(path string, handler Handler)
Register the Get method, equivalent to AddHandler method “Get”, post, put and other methods function similar.
router := erouter.NewRouterRadix()
router.Get("/ *".func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
// Perform processing
})
Copy the code