Go语言RESTful服务通用组件库
Restful服务公共组件库,目的为帮忙快速开发服务程序,尽可能省去与业务无关的重复代码。
可以只使用个别组件,也可以组合起来当“框架”用。
- fastrest是一些辅助性质的函数/结构的集合。
- fastrest不造重复的轮子。
- fastrest力求足够的简单、开放。
包 | 结构体/方法 | 作用 | 说明 |
---|---|---|---|
restserver/httpserver | http服务组件 | 一套http服务的辅助组件,需要组合http、multiplexer一起使用 | |
restserver/httpserver/stdmiddlewares | http中间件 | 一个http的缓存中间件,支持简单的常见的缓存控制策略 | |
restclient/httpclient | http客户端组件 | 一套http客户端的辅助组件 | |
restcache | Caching | 单个数据的缓存中间件 | 缓存流程的胶水逻辑。 基于SentinelGroup解决缓存实效风暴问题。 简单介绍见这里。 |
MCaching | 批量数据的缓存中间件 | ||
restcache/lrucache | LRUCache | LRU缓存存储 | 实现了restcache的缓存存储接口。 基于LRUMap实现。 |
resterror | 错误处理 | ||
restutils | 常用工具函数 |
s := NewServer(ctx, &http.Server{
Addr: "127.0.0.1:28080",
Handler: ...,
})
addr, err := s.Start(ctx) // 启动监听,开始服务。直至收到SIGTERM、SIGINT信号,或Stop被调用。
fmt.Println("Listen running at:", addr)
s.Stop(ctx) // 结束监听。实际环境应该是内部接收退出信号
<-s.ShutdownNotify()
fmt.Println("Exiting...")
err = s.Wait(ctx) // 等待处理完
fmt.Println("Exited")
type Request struct {
Greeting string `schema:"greeting" json:"greeting" validate:"required"`
}
type Response struct {
Echo string `json:"echo"`
}
var handler http.HandlerFunc = NewGenericsHandler((func(ctx context.Context, req *Request) (*Response, error) {
// do things
// output json body
return &Response{
Echo: req.Greeting,
}, nil
}))
storage := lrucache.NewLRUCache(10000, 10) // 一般也可能是redis客户端
ttlRange := [2]time.Duration{time.Minute * 4, time.Minute * 6}
cacheMiddleware := NewCacheMiddleware(storage, ttlRange, nil)
var handler http.HandlerFunc = cacheMiddleware(func(w http.ResponseWriter, r *http.Request) {
// 缓存未命中,才会执行这里
// ... ...
})
type Request struct {
Greeting string `schema:"greeting"`
}
type Response struct {
Echo string `json:"echo"`
}
request := Request{Greeting: "Hi"}
response := Response{}
_ = Get(context.TODO(), &response, s.URL+"/path", request)
type Request struct {
Greeting string `json:"greeting"`
}
type Response struct {
Echo string `json:"echo"`
}
request := Request{Greeting: "Hi"}
response := Response{}
_ = PostJson(context.TODO(), &response, s.URL+"/path", request)
query := func(ctx context.Context, destPtr interface{}, args interface{}) (found bool, err error) {
// 如果Storage没找到,这里提供
// 一般是从持久化数据库、服务接口查询
return true, nil
}
caching := Caching{
Storage: lrucache.NewLRUCache(10000, 10), // 一般是redis实现。透明处理业务数据。
Query: query,
TTLRange: [2]time.Duration{time.Minute * 4, time.Minute * 6},
SentinelTTL: time.Second,
}
var resp Response
var key = "key"
var args = ? // 给query函数的参数
found, err := caching.Get(context.TODO(), &resp, key, args)
query := func(ctx context.Context, destSlicePtr interface{}, argsSlice interface{}) (missIndexes []int, err error) {
// 如果Storage没找到,这里提供
// 一般是从持久化数据库、服务接口查询
// destSlicePtr为接收结果的切片的指针,argsSlice为入参切片
// missIndexes是没查到的下标
return missIndexes, nil
}
mcaching := MCaching{
MStorage: lrucache.NewLRUCache(10000, 10), // 一般是redis实现
MQuery: query,
TTLRange: [2]time.Duration{time.Minute * 4, time.Minute * 6},
SentinelTTL: time.Second,
}
var keys = []string{......}
var args = ...... // 给query函数的参数切片
var resp []*response
missIndexes, err := mcaching.MGet(context.TODO(), &resp, keys, args)
for _, missIndex := range missIndexes {
// not found: keys[missIndex]
}