README
¶
Tux
计划成为优秀的 Rest API 专用框架 (Tux 只是因为那只企鹅)
目前 Tux 处于开发阶段, Rest 模块功能并未完善
目标和上手指南
目标
做这个是想做一个专门用于 Rest API 的框架, 因为在之前听到了不少吐槽现在 Gin + Swagger 开发 Rest 框架的声音, 所以就想做一个专门用于 Rest API 的框架, 用 Golang 的风格去约束并集成 Swagger 以及抽象 Rest 接口, 让开发者能专注于业务逻辑/Service
的开发.
不过由于拖延症以及最近工期的原因一直没有时间去写, 所以现在只是一个简单的 Web 框架, 也是昨天在 V2ex 看到 uRouter
的 Benchmark 代码后用他的代码测试出这个项目的路由树性能好像还不错, 才想起来我好像写了小半年一直没发布...
上手指南
目前整个 Router 和 Context 都是 Gin 风格, 所以有一定的 Gin 使用经验的话, 上手会比较快. 不过我还没写内置 Middleware, 所以目前只能自己写 Middleware, 但是我会尽快补上的.
最简化的 Web 服务:
t := tux.New()
t.Get("/", func (c *tux.Context) {
c.String(http.StatusOK, "Hello World")
})
t.ServeAddr(":8080")
目前还有从郭叔叔的 Gf 框架仿写的 "Rest" 功能, 通过一个结构方法来定义一组 Method
type TestApi struct{}
func (t *TestApi) Get(c *tux.Context) {
c.String(200, "Hello, Get!")
}
func (t *TestApi) Post(c *tux.Context) {
c.String(200, "Hello, Post!")
}
t.Object("/test", &TestApi{})
如果还是没看明白的话这里有一个完整的例子: example
愉快的 Benchmark 时间
使用 uRouter 的 Tree Benchmark 测试结果以及同平台对比
本来想测测 Gin 的但是他好像在重复 Prefix 的时候会直接 panic, 所以就只能对比 uRouter 了...
// tux
go test -benchmem -run=^$ -bench ^(BenchmarkRouteTree_Get|BenchmarkRouteTree_Set)$ tux/tree
goos: linux
goarch: amd64
pkg: tux/tree
cpu: AMD Ryzen 7 5800H with Radeon Graphics
BenchmarkRouteTree_Get-16 126268011 8.905 ns/op 0 B/op 0 allocs/op
BenchmarkRouteTree_Set-16 12803094 93.66 ns/op 1 B/op 0 allocs/op
PASS
ok tux/tree 4.429s
// github.com/lxzan/uRouter
go test -benchmem -run=^$ -bench ^BenchmarkRouteTree_Get$ github.com/lxzan/uRouter
goos: linux
goarch: amd64
pkg: github.com/lxzan/uRouter
cpu: AMD Ryzen 7 5800H with Radeon Graphics
BenchmarkRouteTree_Get-16 4818972 436.4 ns/op 80 B/op 1 allocs/op
PASS
ok github.com/lxzan/uRouter 2.366s
使用 Gin 的 Benchmark 测试结果以及同平台对比
勉强摸到了 Gin 的屁股, 但是仍然无法超过 Gin...明明 Tree 比 Gin 快不少的...有时间看看你不能再去 Context 砍几刀吧...
// tux
go test -benchmem -run=^$ -bench ^(BenchmarkOneRoute|BenchmarkRecoveryMiddleware|BenchmarkLoggerMiddleware|BenchmarkManyHandlers|Benchmark5Params|BenchmarkOneRouteJSON|BenchmarkOneRoutePrintf|BenchmarkOneRouteSet|BenchmarkOneRouteString|BenchmarkManyRoutesFist|BenchmarkManyRoutesLast|Benchmark404|Benchmark404Many)$ tux
goos: linux
goarch: amd64
pkg: tux
cpu: AMD Ryzen 7 5800H with Radeon Graphics
BenchmarkOneRoute-16 22545145 52.80 ns/op 0 B/op 0 allocs/op
BenchmarkRecoveryMiddleware-16 18259539 56.51 ns/op 0 B/op 0 allocs/op
BenchmarkLoggerMiddleware-16 3436378 415.3 ns/op 44 B/op 3 allocs/op
BenchmarkManyHandlers-16 2737478 457.1 ns/op 44 B/op 3 allocs/op
Benchmark5Params-16 9419943 159.9 ns/op 48 B/op 1 allocs/op
BenchmarkOneRouteJSON-16 3760737 309.7 ns/op 32 B/op 2 allocs/op
BenchmarkOneRoutePrintf-16 4094658 328.3 ns/op 96 B/op 2 allocs/op
BenchmarkOneRouteSet-16 3351001 336.3 ns/op 336 B/op 2 allocs/op
BenchmarkOneRouteString-16 11172078 92.32 ns/op 0 B/op 0 allocs/op
BenchmarkManyRoutesFist-16 23754633 50.99 ns/op 0 B/op 0 allocs/op
BenchmarkManyRoutesLast-16 22015323 55.11 ns/op 0 B/op 0 allocs/op
Benchmark404-16 11578872 108.8 ns/op 8 B/op 1 allocs/op
Benchmark404Many-16 9436174 116.7 ns/op 8 B/op 1 allocs/op
PASS
ok tux 19.257s
// github.com/gin-gonic/gin
go test -benchmem -run=^$ -bench ^(BenchmarkOneRoute|BenchmarkRecoveryMiddleware|BenchmarkLoggerMiddleware|BenchmarkManyHandlers|Benchmark5Params|BenchmarkOneRouteJSON|BenchmarkOneRouteHTML|BenchmarkOneRouteSet|BenchmarkOneRouteString|BenchmarkManyRoutesFist|BenchmarkManyRoutesLast|Benchmark404|Benchmark404Many)$ github.com/gin-gonic/gin
goos: linux
goarch: amd64
pkg: github.com/gin-gonic/gin
cpu: AMD Ryzen 7 5800H with Radeon Graphics
BenchmarkOneRoute-16 39173424 30.91 ns/op 0 B/op 0 allocs/op
BenchmarkRecoveryMiddleware-16 33598090 35.66 ns/op 0 B/op 0 allocs/op
BenchmarkLoggerMiddleware-16 743853 1524 ns/op 220 B/op 8 allocs/op
BenchmarkManyHandlers-16 1000000 1834 ns/op 220 B/op 8 allocs/op
Benchmark5Params-16 17871084 69.52 ns/op 0 B/op 0 allocs/op
BenchmarkOneRouteJSON-16 4122009 388.7 ns/op 48 B/op 3 allocs/op
BenchmarkOneRouteHTML-16 945630 2294 ns/op 256 B/op 9 allocs/op
BenchmarkOneRouteSet-16 3967929 308.7 ns/op 336 B/op 2 allocs/op
BenchmarkOneRouteString-16 5524639 193.7 ns/op 48 B/op 1 allocs/op
BenchmarkManyRoutesFist-16 36296466 30.54 ns/op 0 B/op 0 allocs/op
BenchmarkManyRoutesLast-16 37410177 31.74 ns/op 0 B/op 0 allocs/op
Benchmark404-16 25092416 44.37 ns/op 0 B/op 0 allocs/op
Benchmark404Many-16 23788837 50.29 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/gin-gonic/gin 20.164s
Documentation
¶
Index ¶
- Constants
- Variables
- func Normalize(header string) string
- type Context
- func (c *Context) Clean()
- func (c *Context) Close()
- func (c *Context) Cookie(key string) string
- func (c *Context) Data(code int, data []byte)
- func (c *Context) Delete(key string)
- func (c *Context) End()
- func (c *Context) File(code int, ffs fs.FS, filename string)
- func (c *Context) Get(key string) (value interface{}, ok bool)
- func (c *Context) Hijacker(f func(bufrw *bufio.ReadWriter) error) error
- func (c *Context) Index() int
- func (c *Context) JSON(code int, obj any)
- func (c *Context) Next()
- func (c *Context) PostForm(key string) string
- func (c *Context) Query(key string) string
- func (c *Context) ReqBody() (body []byte)
- func (c *Context) Response() (http.ResponseWriter, error)
- func (c *Context) ResponseExported() bool
- func (c *Context) Set(key string, value interface{})
- func (c *Context) SetHeader(key string, value string)
- func (c *Context) Sprintf(code int, format string, values ...any)
- func (c *Context) Status(code ...int) int
- func (c *Context) String(code int, format string)
- func (c *Context) WriteTo(w io.Writer) (int64, error)
- func (c *Context) XML(code int, obj any)
- type Group
- func (g *Group) Any(part string, handler HandlerFunc)
- func (g *Group) Delete(part string, handler HandlerFunc)
- func (g *Group) Get(part string, handler HandlerFunc)
- func (g *Group) GroupTx(prefix string, f func(g *Group))
- func (g *Group) Head(part string, handler HandlerFunc)
- func (g *Group) Method(method, part string, handler HandlerFunc)
- func (g *Group) NewGroup(prefix string) *Group
- func (g *Group) Object(part string, object interface{})
- func (g *Group) Options(part string, handler HandlerFunc)
- func (g *Group) Patch(part string, handler HandlerFunc)
- func (g *Group) Post(part string, handler HandlerFunc)
- func (g *Group) Put(part string, handler HandlerFunc)
- func (g *Group) Use(middleware ...HandlerFunc)
- type HandlerFunc
- type HandlerList
- type HandlerWriter
- type Tux
Constants ¶
const ( HeaderAccept = "Accept" HeaderAcceptCharset = "Accept-Charset" HeaderAcceptEncoding = "Accept-Encoding" HeaderAcceptLanguage = "Accept-Language" HeaderAuthorization = "Authorization" HeaderCacheControl = "Cache-Control" HeaderContentLength = "Content-Length" HeaderContentMD5 = "Content-MD5" HeaderContentType = "Content-Type" HeaderDoNotTrack = "DNT" HeaderIfMatch = "If-Match" HeaderIfModifiedSince = "If-Modified-Since" HeaderIfNoneMatch = "If-None-Match" HeaderIfRange = "If-Range" HeaderIfUnmodifiedSince = "If-Unmodified-Since" HeaderMaxForwards = "Max-Forwards" HeaderProxyAuthorization = "Proxy-Authorization" HeaderPragma = "Pragma" HeaderRange = "Range" HeaderReferer = "Referer" HeaderUserAgent = "User-Agent" HeaderTE = "TE" HeaderVia = "Via" HeaderWarning = "Warning" HeaderCookie = "Cookie" HeaderOrigin = "Origin" HeaderAcceptDatetime = "Accept-Datetime" HeaderXRequestedWith = "X-Requested-With" HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin" HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods" HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers" HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials" HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers" HeaderAccessControlMaxAge = "Access-Control-Max-Age" HeaderAccessControlRequestMethod = "Access-Control-Request-Method" HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers" HeaderAcceptPatch = "Accept-Patch" HeaderAcceptRanges = "Accept-Ranges" HeaderAllow = "Allow" HeaderContentEncoding = "Content-Encoding" HeaderContentLanguage = "Content-Language" HeaderContentLocation = "Content-Location" HeaderContentDisposition = "Content-Disposition" HeaderContentRange = "Content-Range" HeaderETag = "ETag" HeaderExpires = "Expires" HeaderLastModified = "Last-Modified" HeaderLink = "Link" HeaderLocation = "Location" HeaderP3P = "P3P" HeaderProxyAuthenticate = "Proxy-Authenticate" HeaderRefresh = "Refresh" HeaderRetryAfter = "Retry-After" HeaderServer = "Server" HeaderSetCookie = "Set-Cookie" HeaderStrictTransportSecurity = "Strict-Transport-Security" HeaderTransferEncoding = "Transfer-Encoding" HeaderUpgrade = "Upgrade" HeaderVary = "Vary" HeaderWWWAuthenticate = "WWW-Authenticate" // Non-Standard HeaderXFrameOptions = "X-Frame-Options" HeaderXXSSProtection = "X-XSS-Protection" HeaderContentSecurityPolicy = "Content-Security-Policy" HeaderXContentSecurityPolicy = "X-Content-Security-Policy" HeaderXWebKitCSP = "X-WebKit-CSP" HeaderXContentTypeOptions = "X-Content-Type-Options" HeaderXPoweredBy = "X-Powered-By" HeaderXUACompatible = "X-UA-Compatible" HeaderXForwardedProto = "X-Forwarded-Proto" HeaderXHTTPMethodOverride = "X-HTTP-Method-Override" HeaderXForwardedFor = "X-Forwarded-For" HeaderXRealIP = "X-Real-IP" HeaderXCSRFToken = "X-CSRF-Token" HeaderXRatelimitLimit = "X-Ratelimit-Limit" HeaderXRatelimitRemaining = "X-Ratelimit-Remaining" HeaderXRatelimitReset = "X-Ratelimit-Reset" StatusOK = 200 )
HTTP headers
Variables ¶
var ( ErrWriterAlreadyExported = errors.New("writer already exported") ErrResponseAlreadySent = errors.New("response already sent") )
Functions ¶
Types ¶
type Context ¶
type Context struct { Req *http.Request // 公开请求 Writer *HandlerWriter // 公开响应 // contains filtered or unexported fields }
Handler 上下文
func (*Context) Close ¶
func (c *Context) Close()
重置请求, 并跳过后续的HandlerFunc 将无任何输出, 并且浏览器显示连接已重置 但是仍然有响应头 "HTTP 1.1 400 Bad Request\r\nConnection: close"
func (*Context) Hijacker ¶
func (c *Context) Hijacker(f func(bufrw *bufio.ReadWriter) error) error
Hijacker 接口封装 用于将writer转换为bufio.ReadWriter 一旦调用此函数, 其他输出函数将无效 并且此函数关闭时将调用End方法结束请求
func (*Context) ResponseExported ¶
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
路由组
func (*Group) Any ¶
func (g *Group) Any(part string, handler HandlerFunc)
func (*Group) Delete ¶
func (g *Group) Delete(part string, handler HandlerFunc)
func (*Group) Get ¶
func (g *Group) Get(part string, handler HandlerFunc)
func (*Group) Head ¶
func (g *Group) Head(part string, handler HandlerFunc)
func (*Group) Method ¶
func (g *Group) Method(method, part string, handler HandlerFunc)
func (*Group) Options ¶
func (g *Group) Options(part string, handler HandlerFunc)
func (*Group) Patch ¶
func (g *Group) Patch(part string, handler HandlerFunc)
func (*Group) Post ¶
func (g *Group) Post(part string, handler HandlerFunc)
func (*Group) Put ¶
func (g *Group) Put(part string, handler HandlerFunc)
func (*Group) Use ¶
func (g *Group) Use(middleware ...HandlerFunc)
type HandlerFunc ¶
type HandlerFunc func(*Context)
type HandlerList ¶
type HandlerList []HandlerFunc
type HandlerWriter ¶
type HandlerWriter struct {
// contains filtered or unexported fields
}
func (*HandlerWriter) Header ¶
func (w *HandlerWriter) Header() http.Header
func (*HandlerWriter) WriteHeader ¶
func (w *HandlerWriter) WriteHeader(code int)
type Tux ¶
type Tux struct { *Group // 路由组 // contains filtered or unexported fields }
func (*Tux) ExportRoute ¶
func (tux *Tux) ExportRoute() []*tree.ExportValue[HandlerList]