iris
context中断原理
// I don't set to a max value because we want to be able to reuse the handlers even if stopped with .Skip
const stopExecutionIndex = -1
// StopExecution if called then the following .Next calls are ignored,
// as a result the next handlers in the chain will not be fire.
func (ctx *context) StopExecution() {
ctx.currentHandlerIndex = stopExecutionIndex
}
// IsStopped checks and returns true if the current position of the context is -1,
// means that the StopExecution() was called.
func (ctx *context) IsStopped() bool {
return ctx.currentHandlerIndex == stopExecutionIndex
}
func DefaultNext(ctx Context) {
if ctx.IsStopped() {
return
}
if n, handlers := ctx.HandlerIndex(-1)+1, ctx.Handlers(); n < len(handlers) {
ctx.HandlerIndex(n)
handlers[n](ctx)
}
}
func (ctx *context) HandlerIndex(n int) (currentIndex int) {
if n < 0 || n > len(ctx.handlers)-1 {
return ctx.currentHandlerIndex
}
ctx.currentHandlerIndex = n
return n
}
memcache中间件
import (
"bytes"
"net/http"
"sync"
"github.com/bradfitz/gomemcache/memcache"
"github.com/kataras/iris/v12/context"
)
var memcacheClientMux sync.Mutex
var memcacheClient *memcache.Client
// TODO,要不要带上http头部,例如:数据类型html/json/js,Date,Cache-control等等
type middleResp struct {
// 匿名包括,变相继承
http.ResponseWriter
isOK bool
key string
expiration int32
// 如果匿名包括,变相继承会和ResponseWriter冲突,导致接口重复写
b bytes.Buffer
}
var StoreErrHandler func(error)
func (mr *middleResp) writeStore() {
if mr.b.Len() > 0 {
err := memcacheClient.Set(&memcache.Item{
Key: mr.key,
Flags: 0,
Expiration: mr.expiration,
Value: mr.b.Bytes(),
})
if StoreErrHandler != nil {
StoreErrHandler(err)
}
}
}
func (mr *middleResp) Write(body []byte) (int, error) {
if mr.isOK && memcacheClient != nil {
_, err := mr.b.Write(body)
if StoreErrHandler != nil {
StoreErrHandler(err)
}
}
return mr.ResponseWriter.Write(body)
}
func (mr *middleResp) WriteHeader(statusCode int) {
mr.isOK = statusCode == http.StatusOK
mr.ResponseWriter.WriteHeader(statusCode)
}
func MemcacheStore(server string, expireSecond int32) context.Handler {
return MemcacheWrap(server, expireSecond, func(c context.Context) { c.Next() })
}
func MemcacheWrap(server string, expireSecond int32, handler context.Handler) context.Handler {
memcacheClientMux.Lock()
defer memcacheClientMux.Unlock()
if memcacheClient == nil {
memcacheClient = memcache.New(server)
}
return func(c context.Context) {
mr := &middleResp{
ResponseWriter: c.ResponseWriter().Naive(),
key: c.Request().RequestURI,
expiration: expireSecond,
}
c.ResponseWriter().BeginResponse(mr)
handler(c)
mr.writeStore()
}
}
main使用
import (
"math/rand"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/recover"
)
func main() {
app := iris.New()
booksAPI := app.Party(
"/iris/books",
recover.New(),
MemcacheStore("127.0.0.1:11211", 60),
)
{
booksAPI.Get("/", list)
}
app.Get("/iris/other", MemcacheWrap("127.0.0.1:11211", 60, other))
app.Listen(":9090")
}
func other(ctx iris.Context) {
ctx.HTML(
"<H1>%s, %v</H1>",
ctx.Request().RequestURI,
rand.Int(),
)
}
// Book example.
type Book struct {
Title string `json:"title"`
}
func list(ctx iris.Context) {
books := []Book{
{"Mastering Concurrency in Go"},
{"Go Design Patterns"},
{"Black Hat Go"},
}
// ctx.JSON(books)
ctx.HTML("%v", books)
// TIP: negotiate the response between server's prioritizes
// and client's requirements, instead of ctx.JSON:
// ctx.Negotiation().JSON().MsgPack().Protobuf()
// ctx.Negotiate(books)
}