tux

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2023 License: MIT Imports: 16 Imported by: 0

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

View Source
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

View Source
var (
	ErrWriterAlreadyExported = errors.New("writer already exported")
	ErrResponseAlreadySent   = errors.New("response already sent")
)

Functions

func Normalize

func Normalize(header string) string

Normalize formats the input header to the formation of "Xxx-Xxx".

Types

type Context

type Context struct {
	Req    *http.Request  // 公开请求
	Writer *HandlerWriter // 公开响应
	// contains filtered or unexported fields
}

Handler 上下文

func (*Context) Clean

func (c *Context) Clean()

清除缓冲区

func (*Context) Close

func (c *Context) Close()

重置请求, 并跳过后续的HandlerFunc 将无任何输出, 并且浏览器显示连接已重置 但是仍然有响应头 "HTTP 1.1 400 Bad Request\r\nConnection: close"

func (*Context) Cookie

func (c *Context) Cookie(key string) string

获取当前请求的Cookit

func (*Context) Data

func (c *Context) Data(code int, data []byte)

输出字节数据 默认content-type为application/octet-stream

func (*Context) Delete

func (c *Context) Delete(key string)

func (*Context) End

func (c *Context) End()

结束请求, 并跳过后续的HandlerFunc 将正常输出缓冲区内容

func (*Context) File

func (c *Context) File(code int, ffs fs.FS, filename string)

func (*Context) Get

func (c *Context) Get(key string) (value interface{}, ok bool)

func (*Context) Hijacker

func (c *Context) Hijacker(f func(bufrw *bufio.ReadWriter) error) error

Hijacker 接口封装 用于将writer转换为bufio.ReadWriter 一旦调用此函数, 其他输出函数将无效 并且此函数关闭时将调用End方法结束请求

func (*Context) Index

func (c *Context) Index() int

handler 调用索引

func (*Context) JSON

func (c *Context) JSON(code int, obj any)

func (*Context) Next

func (c *Context) Next()

循环执行下一个HandlerFunc

func (*Context) PostForm

func (c *Context) PostForm(key string) string

POST Form Value

func (*Context) Query

func (c *Context) Query(key string) string

URL Query

func (*Context) ReqBody

func (c *Context) ReqBody() (body []byte)

func (*Context) Response

func (c *Context) Response() (http.ResponseWriter, error)

func (*Context) ResponseExported

func (c *Context) ResponseExported() bool

func (*Context) Set

func (c *Context) Set(key string, value interface{})

func (*Context) SetHeader

func (c *Context) SetHeader(key string, value string)

设置 header 的简单封装

func (*Context) Sprintf

func (c *Context) Sprintf(code int, format string, values ...any)

占位符填充输出 内部封装了fmt.Sprintf 默认content-type为text/html

func (*Context) Status

func (c *Context) Status(code ...int) int

设置状态码 也可以获取当前设置的状态码 加了魔法, 可以重复设置状态码

func (*Context) String

func (c *Context) String(code int, format string)

输出字符串 默认content-type为text/html

func (*Context) WriteTo

func (c *Context) WriteTo(w io.Writer) (int64, error)

func (*Context) XML

func (c *Context) XML(code int, obj any)

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) GroupTx

func (g *Group) GroupTx(prefix string, f func(g *Group))

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) NewGroup

func (g *Group) NewGroup(prefix string) *Group

func (*Group) Object

func (g *Group) Object(part string, object interface{})

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) Write

func (w *HandlerWriter) Write(b []byte) (int, error)

func (*HandlerWriter) WriteHeader

func (w *HandlerWriter) WriteHeader(code int)

type Tux

type Tux struct {
	*Group // 路由组
	// contains filtered or unexported fields
}

func New

func New() *Tux

func (*Tux) ExportRoute

func (tux *Tux) ExportRoute() []*tree.ExportValue[HandlerList]

func (*Tux) Handle

func (tux *Tux) Handle(c *Context)

func (*Tux) ServeAddr

func (tux *Tux) ServeAddr(addr string) (*http.Server, error)

func (*Tux) ServeHTTP

func (tux *Tux) ServeHTTP(w http.ResponseWriter, req *http.Request)

func (*Tux) ServeListener

func (tux *Tux) ServeListener(l net.Listener) (*http.Server, error)

Directories

Path Synopsis
_examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL