微内核 Go 语言 Web 框架 go-tango

微内核 Go 语言 Web 框架 go-tango

BSD
Google Go
跨平台
2015-01-13
lunny

Tango 是微内核可扩展的Go语言Web框架。

Golang的web框架基本上处于一个井喷期,那么为什么要再造一个轮子。这是因为,目前可扩展性比较强的都是基于函数作为可执行体的,而以结构体作为执行体的框架目前可扩展性都不够强,包括我原先写的框架xweb也是如此。因此,一个全新的框架出来了,先上地址:https://github.com/lunny/tango

初看Tango框架,感觉和Martini及Macaron非常的像。比如这段代码:

package main

import "github.com/lunny/tango"

func main() {
    t := tango.Classic()
    t.Get("/", func() string {
        return "Hello tango!"
    })
    t.Run()
}

这种其实大家都支持的。再看这个吧:

package main        
            
import "github.com/lunny/tango"     
            
type Action struct {}       
func (Action) Get() string {        
    return "Hello tango!"       
}       
            
func main() {       
    t := tango.Classic()        
    t.Get("/", new(Action))     
    t.Run()     
}

Tango同时支持函数和结构体作为执行体,不过主打是结构体,函数只作为兼容而用。下面对Tango的各种功能一一道来。

路由

Tango目前同时支持3种路由规则:

  • 静态路由

tg.Get("/", new(Action))		
  • 命名路由

tg.Get("/:name", new(Action))		

命名路由对应的参数内容可通过ctx.Params().Get(":name")来获得

  • 正则路由

tg.Get("/(.*)", new(Action))		

正则路由对应的参数内容可通过ctx.Params().Get(":0")来获得

这里要注意命名路由和正则路由不可混用。

执行体

同时支持函数执行体和结构体执行体,支持的函数执行体形式如下,可以有零个或一个返回值,返回值由Return插件提供,后面会再提:

func()		
func(http.ResponseWriter, *http.Request)		
func(*tango.Context)		
func(http.Response.Writer)		
func(*http.Request)		

同时支持包含Get,Post,Head,Options,Trace,Patch,Delete,Put作为成员方法的结构体作为执行体。

type Action struct {}		
func (Action) Get() string {		
    return "Get"		
}		
			
func (Action) Post() string {		
    return "Post"		
}		
			
func (Action) Head() string {		
    return "Head"		
}		
			
func (Action) Options() string {		
    return "Options"		
}		
			
func (Action) Trace() string {		
    return "Trace"		
}		
			
func (Action) Patch() string {		
    return "Patch"		
}		
			
func (Action) Delete() string {		
    return "Delete"		
}		
			
func (Action) Put() string {		
    return "Put"		
}		

在使用路由时,可以用对应的方法或者Any来加路由:

t := tango.Classic()		
t.Get("/1", new(Action))		
t.Any("/2", new(Action))		

路由分组

Tango提供了Group来进行路由分组,Group的最简单形式如下:

g := tango.NewGroup()		
g.Get("/1", func() string {		
    return "/1"		
})		
g.Post("/2", func() string {		
    return "/2"		
})		
t := tango.Classic()		
t.Group("/api", g)		

这样访问/api/1就会返回/1,访问/api/2就会返回/2

同时也可以这样:

t := tango.Classic()		
t.Group("/api", func(g *tango.Group) {		
    g.Get("/1", func() string {		
        return "/1"		
    })		
    g.Post("/2", func() string {		
        return "/2"		
    })		
})		

Group也支持子Group:

t := tango.Classic()		
t.Group("/api", func(g *tango.Group) {		
    g.Group("/v1", func(cg *tango.Group) {		
        cg.Get("/1", func() string {		
	    return "/1"		
	})		
	cg.Post("/2", func() string {		
	    return "/2"		
        })		
    })		
})		

最后,Group也支持逻辑分组:

o := tango.Classic()		
o.Group("", func(g *tango.Group) {		
    g.Get("/1", func() string {		
	return "/1"		
    })		
})		
o.Group("", func(g *tango.Group) {		
    g.Post("/2", func() string {		
	return "/2"		
    })		
})		

这样,即使路由间只是逻辑上分开,而并没有上级路径分开,也是可以分成不同的组。

返回值

通过前面的例子,我们会发现,所有执行体函数,可以有一个返回值或者没有返回值。Tango的内部插件ReturnHandler来负责根据函数的第一个返回值的类型来自动的生成输出,默认规则如下:

  • string 返回string,则string会被转换为bytes并写入到ResponseWriter,默认状态码为200

  • []byte 返回[]byte, 则会直接写入ResponseWriter,默认状态码为200

  • error 返回error接口,如果不为nil, 则返回状态码为500,内容为error.Error()

  • AbortError 返回tango.AbortError接口,如果不为nil,则返回状态码为AbortError.Code,内容为AbortError.Error()

当然了,你可以撰写你自己的插件来判断更多的返回值类型。返回值结合tango的一些tricker,可以极大的简化代码,比如:

如果Action结构体包含匿名结构体tango.Json或者tango.Xml,则返回值结果如下:

如果包含tango.Json匿名结构体,则返回头的Content-Type会自动设置为:application/json:

  • 如果返回值为error,则返回值为{“err”: err.Error()},状态码为200

  • 如果返回值为AbortError,则返回值为{“err”: err.Error()},状态码为err.Code()

  • 如果返回值为string,则返回值为{“content”: content},状态码为200

  • 如果返回值为[]byte,则返回值为{“content”: string(content)},状态码为200

  • 如果返回值为map,slice,结构体或其它可自动Json化的内容,则返回值为map自动json对应的值,状态码为200

例如:

type Action struct {		
    tango.Json		
}		
var i int		
func (Action) Get() interface{} {		
    if i == 0 {		
        i = i + 1		
	return map[string]interface{}{"i":i}		
    }		
    return errors.New("could not visit")		
}		
func main() {		
    t := tango.Classic()		
    t.Any("/", new(Action))		
    t.Run()		
}		

以上例子,访问时会始终返回json,第一次访问会返回map,第二次返回error。(注:这里只是演示代码,实际执行i必须加锁)

Compress

Tango拥有一个默认的压缩中间件,可以按照扩展名来进行文件的压缩。同时,你也可以要求某个Action自动或强制使用某种压缩。比如:

type CompressExample struct {		
    tango.Compress // 添加这个匿名结构体,要求这个结构体的方法进行自动检测压缩		
}		
func (CompressExample) Get() string {		
    return fmt.Sprintf("This is a auto compress text")		
}		
o := tango.Classic()		
o.Get("/", new(CompressExample))		
o.Run()		

以上代码默认会检测浏览器是否支持压缩,如果支持,则看是否支持gzip,如果支持gzip,则使用gzip压缩,如果支持deflate,则使用deflate压缩。

type GZipExample struct {		
    tango.GZip // add this for ask compress to GZip, if accept-encoding has no gzip, then not compress		
}		
func (GZipExample) Get() string {		
    return fmt.Sprintf("This is a gzip compress text")		
}		
o := tango.Classic()		
o.Get("/", new(GZipExample))		
o.Run()		

以上代码默认会检测浏览器是否支持gzip压缩,如果支持gzip,则使用gzip压缩,否则不压缩。

type DeflateExample struct {		
    tango.Deflate // add this for ask compress to Deflate, if not support then not compress
}		
func (DeflateExample) Get() string {		
    return fmt.Sprintf("This is a deflate compress text")		
}		
o := tango.Classic()		
o.Get("/", new(DeflateExample))		
o.Run()		

以上代码默认会检测浏览器是否支持deflate压缩,如果支持deflate,则使用deflate压缩,否则不压缩。

Static

Static 让你用一行代码可以完成一个静态服务器。

func main() {		
    t := tango.New(tango.Static())
    t.Run()		
}		

然后,将你的文件放到 ./public 目录下,你就可以通过浏览器放问到他们。比如:

http://localhost/images/logo.png  --> ./public/images/logo.png		

当然,你也可以加入你basicauth或者你自己的认证中间件,这样就变为了一个私有的文件服务器。

func main() {		
    t := tango.New()		
    t.Use(AuthHandler)		
    t.Use(tango.Static())		
    t.Run()		
}		

Handler

Handler 是tango的中间件。在tango中,几乎所有的事情都由中间件来完成。撰写一个你自己的中间件非常简单,并且我们鼓励您只加载需要的中间件。

tango的中间件只需要符合以下接口即可。

type Handler interface {		
    Handle(*tango.Context)		
}		

同时,tango也提供了tango.HandlerFunc,以方便你将一个函数包装为中间件。比如:

func MyHandler() tango.HandlerFunc {		
    return func(ctx *tango.Context) {		
        fmt.Println("this is my first tango handler")		
	ctx.Next()		
    }		
}		
t := tango.Classic()		
t.Use(MyHandler())		
t.Run()		

正常的形式也可以是:

type HelloHandler struct {}		
func (HelloHandler) Handle(ctx *tango.Context) {		
    fmt.Println("before")		
    ctx.Next()		
    fmt.Println("after")		
}		
t := tango.Classic()		
t.Use(new(HelloHandler))		
t.Run()		

当然,你可以直接将一个包含tango.Context指针的函数作为中间件,如:

tg.Use(func(ctx *tango.Context){		
    fmt.Println("before")		
    ctx.Next()		
    fmt.Println("after")		
})		

为了和标准库兼容,tango通过UseHandler支持http.Handler作为中间件,如:

tg.UseHandler(http.Handler(func(resp http.ResponseWriter, req *http.Request) {		
}))		

老的中间件会被action被匹配之前进行调用。

Call stack

以下是中间件的调用顺序图:

tango.ServeHttp		
	|--Handler1		
		|--Handler2		
			|-- ...HandlerN		
			        |---Action(If matched)		
			...HandlerN--|		
		Handler2 ----|		
	Handler1--|		
(end)--|		

在中间件中,您的中间件代码可以在Next()被调用之前或之后执行,Next表示执行下一个中间件或Action被执行(如果url匹配的话)。如果不调用Next,那么当前请求将会被立即停止,之后的所有代码将不会被执行。

注入

更多的注入方式参见以下示例代码:

Request

type Action struct {		
    tango.Req		
}		

Response

type Action struct {		
    tango.Resp		
}		

Context

type Action struct {		
    tango.Ctx		
}		

Logger

type Action struct {		
    tango.Log		
}		

Params

type Action struct {		
    tango.Params		
}		

Json

type Action struct {		
    tango.Json		
}		

Xml

type Action struct {		
    tango.Xml		
}		

第三方插件

目前已经有了一批第三方插件,更多的插件正在陆续开发中,欢迎大家进行贡献:

案例

  • Wego - golanghome.com论坛的修改版

  • ABlog - 一个新型博客

的码云指数为
超过 的项目
加载中

评论(1)

咚往咚来
咚往咚来
赞~ go-tango

Tango v0.4 版本发布,带来统一高性能的新路由

# 起子 自Tango发布之后大概有3个月了,受到了很多人的关注,也提了很多的改进意见。我自己也通过不断 的用他开发,从而发现问题,不断改进。昨天我发布了0.4.0版本,很明显,最近版本号升得...

2015/04/06 15:47

没有更多内容

加载失败,请刷新页面

没有更多内容

暂无问答

还有比这更全的Android代码与驱动吗?

一、Camera(拍照,录像,编码) 1、tango_donut/packages/apps/Camera(拍照和录像的界面) a) tango_donut/packages/apps/Camera/src/com/android/camera/VideoCamera.java 2、tango_donut/fra...

2012/03/15 14:27
569
0
Google 将在18年 3 月关闭增强现实项目

Google 宣布将于18年 3 月 1 日关闭增强现实项目 Project Tango。Project Tango 是搜索巨人在 2014 年公布的一个项目,借助传感器和相机赋予移动设备感知周围空间和运动能力的项目。它需要专...

2018/01/15 10:37
3
0
Samba(MIPSEL)交叉编译

所需软件包: samba-3.3.3.tar.tar 环境变量: export LD_LIBRARY_PATH=/root/cs_rootfs_1.0.3/cross_rootfs/lib export CPPFLAGS=-I/root/cs_rootfs_1.0.3/cross_rootfs/include export CF...

2016/08/02 18:38
4
0
编程之美之寻找发帖“水王” 的算法问题

Tango是微软亚洲研究 院的一个试验项目。研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango有一大“水王”,他不但喜欢发贴,还会回复其他ID发的每 个帖子。坊间风闻该“水王...

2013/03/12 18:11
322
0
让你轻松实现linux下挂在windows下的ntfs硬盘

NTFS-3g是一款linux下挂在windows的ntfs类型硬盘的工具,本文讲诉如何交叉编译此工具. NTFS-3g交叉移植 所需代码: ntfs-3g-2009.4.4.tar ./configure --host=mipsel-linux 拷贝: cp /tang...

2016/08/02 18:38
3
0
Windows phone 8 开发环境搭建

从微软发布 Windows phone 8 SDK发布以来, 就非常研究一下;很无耐Wp8对开发环境要求比较苛刻。 系统 Windows 8 x64 RAM 4G以上 WP8支持XAMLC#/VB、native C++/C和HTML5三种代码进行开发。开...

2013/01/30 16:21
456
1
Django resources list

自己觉得好的资源,各位有啥好的推荐~ 1. Definitly the first is [Django documentation](https://docs.djangoproject.com/en/1.5/) 2. For a more clear and concise reference [django ch...

2014/03/27 19:22
26
0
Tomcat 6.0配置数据源(DBCP)和JNDI使用

JNDI : Java Naming and Directory Interface (JNDI) JNDI works in concert with other technologies in the Java Platform, Enterprise Edition (Java EE) to organize and locate compone...

2013/01/16 23:28
311
0
YII框架下SRBAC的安装、配置、使用详解

安装篇: 下载Yii扩展插件Srbac提供下载地址: http://www.yiiframework.com/extension/srbac/ http://code.google.com/p/srbac/downloads/list 下载完成之后直接将压缩包的文件srbac文件包拷贝...

2013/01/24 22:57
1K
0

没有更多内容

加载失败,请刷新页面

返回顶部
顶部