优秀 Go 项目介绍: Gorilla web toolkit

原创
2013/08/02 16:33
阅读数 6.8K

Gorilla web toolkit

源码托管地址 Gorilla, 官方网站 gorillatoolkit.

Gorilla 在 Github 上是一个开源组, 值得敬佩的是, 这个小组开发出了多个实用并且独立并解耦的 package. 详情查看官网和源码, 这里做一个简单的介绍.

schema

不要被 schema 这个名字迷惑, 这其实是一个 form 提交数据到 struct 实例的转换器. 非常实用的一个功能. 使用也非常简单. 但是如果您查看源码发现没有引入 net/http 包, 这就是解耦. 因为 http.Request.Form 其实就是一个 map[string][]string 类型.

代码说话

<!-- lang: cpp -->
package main

import (
	"fmt"
	"github.com/gorilla/schema"
)

type Person struct {
	Name  string
	Phone string
}

func main() {
    // 模拟一个 Form 数据
	values := map[string][]string{
		"Name":  {"John"},
		"Phone": {"999-999-999"},
	}
	person := new(Person)
	decoder := schema.NewDecoder()
	decoder.Decode(person, values) // 从Form数据 SetTo *Person
	fmt.Printf("%#v\n", person)
}

是不是很简单, 其代码实现也很简单. 而且 Schema 还提供了注册转换函数

<!-- lang: cpp -->
type Converter func(string) reflect.Value
func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter)

比如我们常见的 time.Time 类型, 因为 layout 的多样性, 可以根据我们的应用写独立的转换函数

<!-- lang: cpp -->

func StringToTime(s string) reflect.Value {
	t, _ := time.Parse("2006-01-02", s)
	return reflect.ValueOf(t)
}
type Person struct {
	Name  string
	Phone string
}

func main() {
    // 模拟一个 Form 数据
	values := map[string][]string{
		"Name":  {"John"},
		"Phone": {"999-999-999"},
            "Day":     {"2013-02-01"},
	}
	person := new(Person)
	decoder := schema.NewDecoder()
    decoder.RegisterConverter(time.Now(), StringToTime)
	decoder.Decode(person, values) // 从Form数据 SetTo *Person
	fmt.Printf("%#v\n", person)
}

实用, 简单, 解耦

context

context 把变量值关联 *http.Request 存储的工具. 看源码

data = make(map[*http.Request]map[interface{}]interface{})

就是一个 map.如果您熟悉jQuery,那这个工具和 jQuery.fn.data 有异曲同工之妙.

代码说话, 直接看 test

当然一定要记住 Clear(r). 因为每一个 *http.Request 都是新的. 害怕忘记, 不要紧context提供了 ClearHandler, 可以对http.Handler进行包装,代码很简单

<!-- lang: cpp -->
func ClearHandler(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer Clear(r)
        h.ServeHTTP(w, r)
    })
}

http.Handler 结束后自动Clear. 反之如果 Request 结束了. 服务器端内存中还保留着 data[*http.Request], 这是不合理的. 这个实现其实非常简单, 而且是并发安全的. 很明显某些场合下, 这会让共享参数变的简单. 有意思的地方是你会如何用她, 会产生什么样的效果.

securecookie

securecookie 通过 HMAC 算法, 实现了对数据进行安全可逆编码(加密). 名字里面虽然带有cookie, 其实并没有绑定必须使用 cookie. 只是表示加密后的数据用于 cookie 也没有问题.

session

session 综合了 context,securecookie 完成了会话数据存储支持. 内建提供 cookiesfilesystem. 当然也预留了Store 接口

<!-- lang: cpp -->
type Store interface {
    Get(r *http.Request, name string) (*Session, error)
    New(r *http.Request, name string) (*Session, error)
    Save(r *http.Request, w http.ResponseWriter, s *Session) error
}

使用者完全可以自己实现一个. 别忘了, 前面介绍的 ClearHandler 的作用.

mux

mux 是一个 Request 路由器分派器( 大家习惯上讲路由 router ). mux doc 非常的强大.

代码说话

<!-- lang: cpp -->
r := mux.NewRouter()
r.Host("{subdomain}.domain.com").
  Path("/articles/{category}/{id:[0-9]+}").
  HandlerFunc(ArticleHandler).
  Name("article")
// url.String() will be "http://news.domain.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news","category", "technology","id", "42")

功能不完全列举

  • 支持正则
  • 前缀路由 r.PathPrefix("/products/") 匹配所有 "/products/" 开头的 Request
  • Method 路由 r.Methods("get") 匹配 GET 请求
  • 子路由 r.PathPrefix("/products").Subrouter(), 这样与前缀路由(或者其他,比如Method)配合, 可以更细致的控制
  • URL parameter s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) ,解析路径中的变量
  • Host 路由 r.Host("{subdomain}.domain.com"), 是的,子域名匹配什么的就这么简单
  • StrictSlash,访问 "/path" 实际到 "/path/", 其实问题很复杂, 看了net/http的代码,你就理解了.
  • 组合路由, 各种路由组合到一起不可思议的安逸.
展开阅读全文
加载中

作者的其它热门文章

打赏
2
5 收藏
分享
打赏
1 评论
5 收藏
2
分享
返回顶部
顶部