Высокопроизводительная и расширяемая библиотека http-маршрутизации golang erouter

Go

erouter

Go Report Card
GoDoc

erouter — это высокопроизводительная и расширяемая библиотека http-маршрутизации с нулевым копированием памяти, строгим порядком сопоставления маршрутизации, низким дублированием кода, групповой маршрутизацией, функциями промежуточного программного обеспечения, параметрами по умолчанию, сопоставлением констант, сопоставлением переменных, сопоставлением подстановочных знаков, сопоставлением проверки переменных, подстановочными знаками. Проверьте сопоставление и маршрутизацию на основе хоста.

Примечания к дизайну

на основеeudoreРазделение маршрутов фреймворка, модификация механизма промежуточного программного обеспечения и удаление MVC.

RouterRadix

RouterRadix реализован с использованием radix-дерева, с нулевым копированием памяти, строгим порядком сопоставления маршрутизации, групповой маршрутизацией, функциями промежуточного программного обеспечения, параметрами по умолчанию, сопоставлением констант, сопоставлением переменных и функциями сопоставления подстановочных знаков.

example:

package main

import "log"
import "net/http"
import "github.com/eudore/erouter"

func main() {
	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)
}

Тестовая команда:

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/getuser

RouterFull

Основанный на расширении RouterRadix, RouterFull реализует функции проверки и сопоставления переменных, а также проверки и сопоставления с подстановочными знаками.

Использование: после обычных переменных и подстановочных знаков используйте символ «|» для разделения, за которым следует правило проверки, isnum — функция проверки, min:100 — функция динамической проверки, min — имя функции динамической проверки, а ':' - это параметр; если он начинается с '^', это обычная проверка и заканчивается '$'.

Примечание. Не используйте пробелы в регулярных выражениях, это приведет к ошибкам сегментации параметров, используйте \u002 вместо пробелов.

:num|isnum
:num|min:100
:num|^0.*$
*num|isnum
*num|min:100
*num|^0.*$

example:

package main

import "net/http"
import "github.com/eudore/erouter"

func main() {
	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)
}

Тестовая команда:

curl 127.0.0.1:8080/get
curl 127.0.0.1:8080/012
curl 127.0.0.1:8080/123
curl 127.0.0.1:8080/12
curl 127.0.0.1:8080/Erouter/123

RouterHost

RouterHost основан на сопоставлении узлов и реализует функцию маршрутизации на основе узлов путем выбора соответствующего подмаршрутизатора узла для выполнения регистрации и сопоставления.

В настоящее время используется сопоставление обхода, функция сопоставления хостаpath.Match, будущие правила сопоставления сохраняют только подстановочные знаки '*' и константы.

Использование: вам необходимо зарегистрировать подмаршрутизаторы в соответствии с правилами доменного имени для хост-маршрутизатора.При регистрации маршрутов используйте параметр хоста для сопоставления зарегистрированных маршрутизаторов для добавления маршрутов и используйте запрошенный хост для сопоставления зарегистрированных маршрутов при сопоставлении.

example:

package main

import "net/http"
import "github.com/eudore/erouter"

func main() {
	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)
}

Тестовая команда:

curl 127.0.0.1:8080
curl -XPUT 127.0.0.1:8080
curl -H 'Host: www.example.com' 127.0.0.1:8080
curl -H 'Host: www.example.com' -XPUT 127.0.0.1:8080
curl -H 'Host: www.example.com' -Xput 127.0.0.1:8080

Benchmark

Используйте GithubApi дляКонтрольный тест производительности, производительность сопоставления Erouter составляет всего 60% от производительности httprouter, но он обладает характеристиками строгого порядка сопоставления маршрутизации, простоты расширения и перезаписи и низкой сложности кода.

Тестовая команда:

go get github.com/eudore/web-framework-benchmark
go test -bench=router github.com/eudore/web-framework-benchmark

Результаты теста:

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.934s

Api

Перечисляет основные используемые методы, конкретные ссылкиДокументация.

Определение интерфейса маршрутизатора:

type (
	// Params读写请求处理中的参数。
	Params interface {
		GetParam(string) string
		AddParam(string, string)
		SetParam(string, string)
	}
	// Erouter处理一个请求的方法,在http.HandlerFunc基础上增加了Parmas。
	Handler func(http.ResponseWriter, *http.Request, Params)
	// 定义请求处理中间件函数,通过传入处理然后返回一个处理,使用装饰器组装处理请求。
	Middleware func(Handler) Handler
	// The route is directly registered by default. Other methods can be directly registered using the RouterRegister interface.
	//
	// 路由默认直接注册的方法,其他方法可以使用RouterRegister接口直接注册。
	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.
	//
	// 路由器核心接口,执行路由、中间件的注册和处理http请求。
	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.
	//
	// 路由器接口,需要实现路由器方法、路由器核心两个接口。
	Router interface {
		RouterCore
		RouterMethod
	}
)

NewRouter

В настоящее время существует три реализации, каждая из которых реализует интерфейс маршрутизатора.

func NewRouterRadix() Router
func NewRouterFull() Router
func NewRouterHost() Router
router1 := erouter.NewRouterRadix()
router2 := erouter.NewRouterFull()
router3 := erouter.NewRouterHost()

Group

func Group(path string) RouterMethod

Группа реализует группировку маршрутизаторов.

router := erouter.NewRouterRadix()
apiv1 := router.Group("/api/v1 version=v1")
apiv1.Get("/*", ...)

AddHandler

func AddHandler(method string, path string, handler Handler) RouterMethod

AddHandler используется для добавления новых маршрутов.

router := erouter.NewRouterRadix()
router.AddHandle("GET", "/*", ...)

AddMiddleware

func AddMiddleware(method string, path string, midds ...Middleware) RouterMethod

AddMiddleware добавляет ПО промежуточного слоя обработки к текущему методу маршрутизации.

router := erouter.NewRouterRadix()
router.AddMiddleware("ANY", "", func(h erouter.Handler) erouter.Handler {
	return func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
		// befor执行
		...
		// 调用next处理汇总函数
		h(w, r, p)
		// after执行
		...
	}
})

NotFound

func NotFound(Handler)

Настройте маршрутизатор 404 для обработки.

MethodNotAllowed

func MethodNotAllowed(Handler)

Настройка маршрутизатора 405 ручек.

Any

func Any(path string, handler Handler)

Зарегистрируйте метод Any, который эквивалентен методу AddHandler со значением «ЛЮБОЙ».

Коллекция методов Any — это router.RouterAllMethod, а новые методы расширения Radix и Full не поддерживаются.

Get

func Get(path string, handler Handler)

Регистрация метода Get, эквивалентного методу AddHandler, называется «GET», а функции метода, такие как post и put, аналогичны.

router := erouter.NewRouterRadix()
router.Get("/*", func(w http.ResponseWriter, r *http.Request, p erouter.Params) {
	// 执行处理
})