Faygo簡(jiǎn)潔優(yōu)雅的Go Web框架
Faygo(原名Thinkgo)
概述
Faygo以全新的架構(gòu)實(shí)現(xiàn),它面向Handler接口開發(fā),是支持智能參數(shù)映射與校驗(yàn)、支持自動(dòng)化API文檔的Go語(yǔ)言web框架。
最新版本
版本號(hào)
v1.0
安裝要求
Go Version ≥1.8
快速使用
方式一 源碼下載
go get -u -v github.com/henrylee2cn/faygo
方式二 部署工具 (Go to fay)
go get -u -v github.com/henrylee2cn/fay
fay command [arguments] The commands are: new 創(chuàng)建、編譯和運(yùn)行(監(jiān)控文件變化)一個(gè)新的faygo項(xiàng)目 run 編譯和運(yùn)行(監(jiān)控文件變化)任意一個(gè)已存在的golang項(xiàng)目 fay new appname [apptpl] appname 指定新faygo項(xiàng)目的創(chuàng)建目錄 apptpl 指定一個(gè)faygo項(xiàng)目模板(可選) fay run [appname] appname 指定待運(yùn)行的golang項(xiàng)目路徑(可選)
框架特性
面向Handler接口開發(fā)(func or struct),中間件與操作完全等同可任意拼接路由操作鏈
支持用struct Handler在Tag標(biāo)簽定義請(qǐng)求參數(shù)信息及其校驗(yàn)信息
支持自動(dòng)構(gòu)建API文檔(swagger2.0)
支持多種網(wǎng)絡(luò)類型:
HTTP
HTTPS/HTTP2(TLS)
HTTPS/HTTP2(Let's Encrypt TLS)
HTTPS/HTTP2(Let's Encrypt TLS on UNIX socket)
HTTP(UNIX socket)
HTTPS/HTTP2(TLS on UNIX socket)
支持多實(shí)例運(yùn)行,且配置信息相互獨(dú)立
支持同一實(shí)例監(jiān)聽多網(wǎng)絡(luò)類型、多端口
基于高性能路由httprouter進(jìn)行二次開發(fā),支持鏈?zhǔn)脚c樹形兩種路由信息注冊(cè)風(fēng)格
強(qiáng)大的文件路由功能,支持自定義文件系統(tǒng),框架提供快捷的DirFS、RenderFS、MarkdownFS等
提供近似LRU的文件緩存功能
跨平臺(tái)的彩色日志系統(tǒng),且同時(shí)支持console和file兩種輸出形式(可以同時(shí)使用)
提供Session管理功能
支持Gzip全局配置
提供XSRF跨站請(qǐng)求偽造安全過(guò)濾
簡(jiǎn)單整潔的配置文件,且自動(dòng)補(bǔ)填默認(rèn)值方便設(shè)置
支持平滑關(guān)閉與重啟
struct Handler的多用途合一
簡(jiǎn)單示例
package main
import (
// "mime/multipart"
"time"
"github.com/henrylee2cn/faygo"
)
type Index struct {
Id int `param:""`
Title string `param:""`
Paragraph []string `param:""`
Cookie string `param:""`
// Picture *multipart.FileHeader `param:""`
}
func (i *Index) Serve(ctx *faygo.Context) error {
if ctx.CookieParam("faygoID") == "" {
ctx.SetCookie("faygoID", time.Now().String())
}
return ctx.JSON(200, i)
}
func main() {
app := faygo.New("myapp", "0.1")
// Register the route in a chain style
app.GET("/index/:id", new(Index))
// Register the route in a tree style
// app.Route(
// app.NewGET("/index/:id", new(Index)),
// )
// Start the service
faygo.Run()
}
/*
http GET:
http://localhost:8080/index/1?title=test&p=abc&p=xyz
response:
{
"Id": 1,
"Title": "test",
"Paragraph": [
"abc",
"xyz"
],
"Cookie": "2016-11-13 01:14:40.9038005 +0800 CST"
}
*/
操作和中間件
操作和中間件是相同的,都是實(shí)現(xiàn)了Handler接口!
函數(shù)類型
// 不含API文檔描述
func Page() faygo.HandlerFunc {
return func(ctx *faygo.Context) error {
return ctx.String(200, "faygo")
}
}
// 含API文檔描述
var Page2 = faygo.WrapDoc(Page(), "測(cè)試頁(yè)2的注意事項(xiàng)", "文本")
結(jié)構(gòu)體類型
// Param操作通過(guò)Tag綁定并驗(yàn)證請(qǐng)求參數(shù)
type Param struct {
Id int `param:""`
Title string `param:""`
}
// Serve實(shí)現(xiàn)Handler接口
func (p *Param) Serve(ctx *faygo.Context) error {
return ctx.JSON(200,
faygo.Map{
"Struct Params": p,
"Additional Param": ctx.PathParam("additional"),
}, true)
}
// Doc實(shí)現(xiàn)API文檔接口(可選)
func (p *Param) Doc() faygo.Doc {
return faygo.Doc{
// 向API文檔聲明接口注意事項(xiàng)
Note: "param desc",
// 向API文檔聲明響應(yīng)內(nèi)容格式
Return: faygo.JSONMsg{
Code: 1,
Info: "success",
},
// 向API文檔增加額外的請(qǐng)求參數(shù)聲明(可選)
Params: []faygo.ParamInfo{
{
Name: "additional",
In: "path",
Model: "a",
Desc: "defined by the `Doc()` method",
},
},
}
}
過(guò)濾函數(shù)
過(guò)濾函數(shù)必須是HandlerFunc類型!
func Root2Index(ctx *faygo.Context) error {
// 不允許直接訪問(wèn)`/index`
if ctx.Path() == "/index" {
ctx.Stop()
return nil
}
if ctx.Path() == "/" {
ctx.ModifyPath("/index")
}
return nil
}
路由注冊(cè)
樹狀
// 新建應(yīng)用實(shí)例,參數(shù):名稱、版本
var app1 = faygo.New("myapp1", "1.0")
// 路由
app1.Filter(Root2Index).
Route(
app1.NewNamedGET("測(cè)試頁(yè)1", "/page", Page()),
app1.NewNamedGET("測(cè)試頁(yè)2", "/page2", Page2),
app1.NewGroup("home",
app1.NewNamedGET("test param", "/param", &Param{
// 為綁定的參數(shù)設(shè)定API文檔中缺省值(可選)
Id: 1,
Title: "test param",
}),
),
)
鏈狀
// 新建應(yīng)用實(shí)例,參數(shù):名稱、版本
var app2 = faygo.New("myapp2", "1.0")
// 路由
app2.Filter(Root2Index)
app2.NamedGET("test page", "/page", Page())
app2.NamedGET("test page2", "/page2", Page2)
app2.Group("home")
{
app2.NamedGET("test param", "/param", &Param{
// 為綁定的參數(shù)設(shè)定API文檔中缺省值(可選)
Id: 1,
Title: "test param",
})
}
平滑關(guān)閉與重啟
平滑關(guān)閉
kill [pid]
平滑重啟
kill -USR2 [pid]
配置文件說(shuō)明
應(yīng)用的各實(shí)例均有單獨(dú)一份配置,其文件名格式
config/{appname}[_{version}].ini,配置詳情:
net_types = http|https # 多種網(wǎng)絡(luò)類型列表,支持 http | https | unix_http | unix_https | letsencrypt | unix_letsencrypt addrs = 0.0.0.0:80|0.0.0.0:443 # 多個(gè)監(jiān)聽地址列表 tls_certfile = # TLS證書文件路徑 tls_keyfile = # TLS密鑰文件路徑 letsencrypt_dir = # Let's Encrypt TLS證書緩存目錄 unix_filemode = 438 # UNIX listener的文件權(quán)限(438即0666) read_timeout = 0 # 讀取請(qǐng)求數(shù)據(jù)超時(shí) write_timeout = 0 # 寫入響應(yīng)數(shù)據(jù)超時(shí) multipart_maxmemory_mb = 32 # 接收上傳文件時(shí)允許使用的最大內(nèi)存 [router] # 路由配置區(qū) redirect_trailing_slash = true # 當(dāng)前請(qǐng)求的URL含`/`后綴如`/foo/`且相應(yīng)路由不存在時(shí),如存在`/foo`,則自動(dòng)跳轉(zhuǎn)至`/foo` redirect_fixed_path = true # 自動(dòng)修復(fù)URL,如`/FOO` `/..//Foo`均被跳轉(zhuǎn)至`/foo`(依賴redirect_trailing_slash=true) handle_method_not_allowed = true # 若開啟,當(dāng)前請(qǐng)求方法不存在時(shí)返回405,否則返回404 handle_options = true # 若開啟,自動(dòng)應(yīng)答OPTIONS類請(qǐng)求,可在Faygo中設(shè)置默認(rèn)Handler [xsrf] # XSRF跨站請(qǐng)求偽造過(guò)濾配置區(qū) enable = false # 是否開啟 key = faygoxsrf # 加密key expire = 3600 # xsrf防偽token有效時(shí)長(zhǎng) [session] # Session配置區(qū)(詳情參考beego session模塊) enable = false # 是否開啟 provider = memory # 數(shù)據(jù)存儲(chǔ)方式 name = faygosessionID # 客戶端存儲(chǔ)cookie的名字 gc_max_lifetime = 3600 # 觸發(fā)GC的時(shí)間 provider_config = # 配置信息,根據(jù)不同的引擎設(shè)置不同的配置信息 cookie_lifetime = 0 # 客戶端存儲(chǔ)的cookie的時(shí)間,默認(rèn)值是0,即瀏覽器生命周期 auto_setcookie = true # 是否自動(dòng)設(shè)置關(guān)于session的cookie值,一般默認(rèn)true domain = # 可以訪問(wèn)此cookie的域名 enable_sid_in_header = false # 是否將session ID寫入Header name_in_header = Faygosessionid # 將session ID寫入Header時(shí)的頭名稱 enable_sid_in_urlquery = false # 是否將session ID寫入url的query部分 [apidoc] # API文檔 enable = true # 是否啟用 path = /apidoc # 訪問(wèn)的URL路徑 nolimit = false # 是否不限訪問(wèn)IP real_ip = false # 使用真實(shí)客戶端的IP進(jìn)行過(guò)濾 whitelist = 192.*|202.122.246.170 # 表示允許帶有`192.`前綴或等于`202.122.246.170`的IP訪問(wèn) desc = # 項(xiàng)目描述 email = # 聯(lián)系人郵箱 terms_url = # 服務(wù)條款URL license = # 協(xié)議類型 license_url = # 協(xié)議內(nèi)容URL
應(yīng)用只有一份全局配置,文件名為
config/__global__.ini,配置詳情:
[cache] # 文件內(nèi)存緩存配置區(qū) enable = false # 是否開啟 size_mb = 32 # 允許緩存使用的最大內(nèi)存(單位MB),為0時(shí)系統(tǒng)自動(dòng)設(shè)置為512KB expire = 60 # 緩存最大時(shí)長(zhǎng) [gzip] # gzip壓縮配置區(qū) enable = false # 是否開啟 min_length = 20 # 進(jìn)行壓縮的最小內(nèi)容長(zhǎng)度 compress_level = 1 # 非文件類響應(yīng)Body的壓縮水平(0-9),注意文件壓縮始終為最優(yōu)壓縮比(9) methods = GET # 允許壓縮的請(qǐng)求方法,為空時(shí)默認(rèn)為GET [log] # 日志配置區(qū) console_enable = true # 是否啟用控制臺(tái)日志 console_level = debug # 控制臺(tái)日志打印水平 file_enable = true # 是否啟用文件日志 file_level = debug # 文件日志打印水平 async_len = 0 # 0表示同步打印,大于0表示異步緩存長(zhǎng)度
Handler結(jié)構(gòu)體字段標(biāo)簽說(shuō)明
| tag | key | required | value | desc |
|---|---|---|---|---|
| param | in | 有且只有一個(gè) | path | (參數(shù)位置)為空時(shí)自動(dòng)補(bǔ)全,如URL http://www.abc.com/a/{path} |
| param | in | 有且只有一個(gè) | query | (參數(shù)位置)如URL http://www.abc.com/a?b={query} |
| param | in | 有且只有一個(gè) | formData | (參數(shù)位置)請(qǐng)求表單,如 a=123&b={formData} |
| param | in | 有且只有一個(gè) | body | (參數(shù)位置)請(qǐng)求Body |
| param | in | 有且只有一個(gè) | header | (參數(shù)位置)請(qǐng)求頭 |
| param | in | 有且只有一個(gè) | cookie | (參數(shù)位置)請(qǐng)求cookie,支持:*http.Cookie、http.Cookie、string、[]byte等 |
| param | name | 否 | (如id) |
自定義參數(shù)名 |
| param | required | 否 | required | 參數(shù)是否必須 |
| param | desc | 否 | (如id) |
參數(shù)描述 |
| param | len | 否 | (如3:63) |
字符串類型參數(shù)的長(zhǎng)度范圍 |
| param | range | 否 | (如0:10) |
數(shù)字類型參數(shù)的數(shù)值范圍 |
| param | nonzero | 否 | nonzero | 是否能為零值 |
| param | maxmb | 否 | (如32) |
當(dāng)前Content-Type為multipart/form-data時(shí),允許使用的最大內(nèi)存,當(dāng)設(shè)置了多個(gè)時(shí)使用較大值 |
| param | regexp | 否 | (如^\w+$) |
使用正則驗(yàn)證參數(shù)值 |
| param | err | 否 | (如密碼格式錯(cuò)誤) |
自定義參數(shù)綁定或驗(yàn)證的錯(cuò)誤信息 |
NOTES:
綁定的對(duì)象必須為結(jié)構(gòu)體指針類型
除
*multipart.FileHeader外,綁定的結(jié)構(gòu)體字段類型不能為指針類型只有在
param:"type(xxx)"存在時(shí),regexp和param標(biāo)簽才有效若
param標(biāo)簽不存在,將嘗試解析匿名字段當(dāng)結(jié)構(gòu)體標(biāo)簽
in為formData且字段類型為*multipart.FileHeader、multipart.FileHeader、[]*multipart.FileHeader或[]multipart.FileHeader時(shí),該參數(shù)接收文件類型當(dāng)結(jié)構(gòu)體標(biāo)簽
in為cookie,字段類型必須為*http.Cookie或http.Cookie標(biāo)簽
in(formData)和in(body)不能同時(shí)出現(xiàn)在同一結(jié)構(gòu)體不能存在多個(gè)
in(body)標(biāo)簽
Handler結(jié)構(gòu)體字段類型說(shuō)明
| base | slice | special |
|---|---|---|
| string | []string | [][]byte |
| byte | []byte | [][]uint8 |
| uint8 | []uint8 | *multipart.FileHeader (僅formData參數(shù)使用) |
| bool | []bool | []*multipart.FileHeader (僅formData參數(shù)使用) |
| int | []int | *http.Cookie (僅net/http下的cookie參數(shù)使用) |
| int8 | []int8 | http.Cookie (僅net/http下的cookie參數(shù)使用) |
| int16 | []int16 | struct (body參數(shù)使用或用于匿名字段擴(kuò)展參數(shù)) |
| int32 | []int32 | |
| int64 | []int64 | |
| uint8 | []uint8 | |
| uint16 | []uint16 | |
| uint32 | []uint32 | |
| uint64 | []uint64 | |
| float32 | []float32 | |
| float64 | []float64 |
擴(kuò)展包
| 擴(kuò)展包 | 導(dǎo)入路徑 |
|---|---|
| 各種條碼 | github.com/henrylee2cn/faygo/ext/barcode |
| 比特單位 | github.com/henrylee2cn/faygo/ext/bitconv |
| gorm數(shù)據(jù)庫(kù)引擎 | github.com/henrylee2cn/faygo/ext/db/gorm |
| sqlx數(shù)據(jù)庫(kù)引擎 | github.com/henrylee2cn/faygo/ext/db/sqlx |
| xorm數(shù)據(jù)庫(kù)引擎 | github.com/henrylee2cn/faygo/ext/db/xorm |
| directSQL(配置化SQL引擎) | github.com/henrylee2cn/faygo/ext/db/directsql |
| 口令算法 | github.com/henrylee2cn/faygo/ext/otp |
| UUID | github.com/henrylee2cn/faygo/ext/uuid |
| Websocket | github.com/henrylee2cn/faygo/ext/websocket |
| ini配置 | github.com/henrylee2cn/faygo/ini |
| 定時(shí)器 | github.com/henrylee2cn/faygo/ext/cron |
| 任務(wù)工具 | github.com/henrylee2cn/faygo/ext/task |
| HTTP客戶端 | github.com/henrylee2cn/faygo/ext/surfer |
開源協(xié)議
Faygo 項(xiàng)目采用商業(yè)應(yīng)用友好的 Apache2.0 協(xié)議發(fā)布。
