gorouter:简单高性能的 Go router
source link: https://github.com/xujiajun/gorouter?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
gorouter
xujiajun/gorouter
is a simple and fast HTTP router for Go. It is easy to build RESTful APIs and your web framework.
Motivation
I wanted a simple, fast router that has no unnecessary overhead using the standard library only, following good practices and well tested code.
Features
- Custom NotFoundHandler
- Middleware Chain Support
- Pattern Rule Familiar
- HTTP Method Get、Post、Delete、Put、Patch Support
- No external dependencies (just Go stdlib)
Requirements
- golang 1.8+
Installation
go get github.com/xujiajun/gorouter
Usage
Static routes
package main import ( "log" "net/http" "github.com/xujiajun/gorouter" ) func main() { mux := gorouter.New() mux.GET("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) }) log.Fatal(http.ListenAndServe(":8181", mux)) }
URL Parameters
package main import ( "github.com/xujiajun/gorouter" "log" "net/http" ) func main() { mux := gorouter.New() //url parameters match mux.GET("/user/:id", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("match user/:id !")) }) log.Fatal(http.ListenAndServe(":8181", mux)) }
Regex Parameters
package main import ( "github.com/xujiajun/gorouter" "log" "net/http" ) func main() { mux := gorouter.New() //url regex match mux.GET("/user/{id:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("match user/{id:[0-9]+} !")) }) log.Fatal(http.ListenAndServe(":8181", mux)) }
Routes Groups
package main import ( "fmt" "github.com/xujiajun/gorouter" "log" "net/http" ) func usersHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "/api/users") } func main() { mux := gorouter.New() mux.Group("/api").GET("/users", usersHandler) log.Fatal(http.ListenAndServe(":8181", mux)) }
Custom NotFoundHandler
package main import ( "fmt" "github.com/xujiajun/gorouter" "log" "net/http" ) func notFoundFunc(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) fmt.Fprint(w, "404 page !!!") } func main() { mux := gorouter.New() mux.NotFoundFunc(notFoundFunc) mux.GET("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) }) log.Fatal(http.ListenAndServe(":8181", mux)) }
Custom PanicHandler
package main import ( "fmt" "github.com/xujiajun/gorouter" "log" "net/http" ) func main() { mux := gorouter.New() mux.PanicHandler = func(w http.ResponseWriter, req *http.Request, err interface{}) { w.WriteHeader(http.StatusInternalServerError) fmt.Println("err from recover is :", err) fmt.Fprint(w, "received a panic") } mux.GET("/panic", func(w http.ResponseWriter, r *http.Request) { panic("panic") }) log.Fatal(http.ListenAndServe(":8181", mux)) }
Middlewares Chain
package main import ( "fmt" "github.com/xujiajun/gorouter" "log" "net/http" ) type statusRecorder struct { http.ResponseWriter status int } func (rec *statusRecorder) WriteHeader(code int) { rec.status = code rec.ResponseWriter.WriteHeader(code) } //https://upgear.io/blog/golang-tip-wrapping-http-response-writer-for-middleware/ func withStatusRecord(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { rec := statusRecorder{w, http.StatusOK} next.ServeHTTP(&rec, r) log.Printf("response status: %v\n", rec.status) } } func notFoundFunc(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) fmt.Fprint(w, "Not found page !") } func withLogging(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Printf("Logged connection from %s", r.RemoteAddr) next.ServeHTTP(w, r) } } func withTracing(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Printf("Tracing request for %s", r.RequestURI) next.ServeHTTP(w, r) } } func main() { mux := gorouter.New() mux.NotFoundFunc(notFoundFunc) mux.Use(withLogging, withTracing, withStatusRecord) mux.GET("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) }) log.Fatal(http.ListenAndServe(":8181", mux)) }
Serve static files
package main import ( "github.com/xujiajun/gorouter" "log" "net/http" "os" ) //ServeFiles serve static resources func ServeFiles(w http.ResponseWriter, r *http.Request) { wd, err := os.Getwd() if err != nil { log.Fatal(err) } dir := wd + "/examples/serveStaticFiles/files" http.StripPrefix("/files/", http.FileServer(http.Dir(dir))).ServeHTTP(w, r) } func main() { mux := gorouter.New() mux.GET("/hi", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hi")) }) //defined prefix mux2 := mux.Group("/files") //http://127.0.0.1:8181/files/demo.txt //will match mux2.GET("/{filename:[0-9a-zA-Z_.]+}", func(w http.ResponseWriter, r *http.Request) { ServeFiles(w, r) }) //http://127.0.0.1:8181/files/a/demo2.txt //http://127.0.0.1:8181/files/a/demo.txt //will match mux2.GET("/{fileDir:[0-9a-zA-Z_.]+}/{filename:[0-9a-zA-Z_.]+}", func(w http.ResponseWriter, r *http.Request) { ServeFiles(w, r) }) log.Fatal(http.ListenAndServe(":8181", mux)) }
Detail see serveStaticFiles example
Pattern Rule
The syntax here is modeled after julienschmidt/httprouter and gorilla/mux
Syntax Description Example:name
named parameter
/user/:name
{name:regexp}
named with regexp parameter
/user/{name:[0-9a-zA-Z]+}
:id
named with regexp parameter
/user/:id
And :id
is short for {id:[0-9]+}
, :name
are short for {name:[0-9a-zA-Z_]+}
Benchmarks
go test -bench=.
Benchmark System:
- Go version 1.9.2
- OS: Mac OS X 10.13.3
- Architecture: x86_64
- 16 GB 2133 MHz LPDDR3
Tested routers:
Result:
➜ gorouter git:(master) ✗ go test -bench=. GithubAPI Routes: 203 GithubAPI2 Routes: 203 HttpRouter: 37464 Bytes GoRouter: 83616 Bytes trie-mux: 135096 Bytes MuxRouter: 1324192 Bytes goos: darwin goarch: amd64 pkg: github.com/xujiajun/gorouter BenchmarkTrieMuxRouter-8 10000 692179 ns/op 1086465 B/op 2975 allocs/op BenchmarkHttpRouter-8 10000 627134 ns/op 1034366 B/op 2604 allocs/op BenchmarkGoRouter-8 10000 630895 ns/op 1034415 B/op 2843 allocs/op BenchmarkMuxRouter-8 10000 6396340 ns/op 1272876 B/op 4691 allocs/op PASS ok github.com/xujiajun/gorouter 83.503s
Conclusions:
-
Performance (xujiajun/gorouter ≈ julienschmidt/httprouter > teambition/trie-mux > gorilla/mux)
-
Memory Consumption (xujiajun/gorouter ≈ julienschmidt/httprouter < teambition/trie-mux < gorilla/mux)
-
Features (xujiajun/gorouter, gorilla/mux and teambition/trie-mux support regexp, But julienschmidt/httprouter not support)
if you want a performance router which support regexp, maybe xujiajun/gorouter is good choice.
Contributing
If you'd like to help out with the project. You can put up a Pull Request.
Author
License
The gorouter is open-sourced software licensed under the MIT Licensed
Acknowledgements
This package is inspired by the following:
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK