文章接上回,来看看框架是怎么执行handler 以及一些其他中间件的
中间件格式
func(resp http.ResponseWriter, req *http.Request)
func(ctx *macaron.Context)
func(resp http.ResponseWriter, req *http.Request,ctx *macaron.Context)
是不是比其他web框架灵活多了(* ̄︶ ̄)
还可以自定义格式
比如先调用c.Map(value),那么中间件就支持这种形式
func(value *valueType)
中间件如何被注册的
回到get 方法
// Get is a shortcut for r.Handle("GET", pattern, handlers)
func (r *Router) Get(pattern string, h ...Handler) (leaf *Route) {
leaf = r.Handle("GET", pattern, h)
if r.autoHead {
r.Head(pattern, h...)
}
return leaf
}
在handle方法中有这么一步
handlers = validateAndWrapHandlers(handlers, r.handlerWrapper)
该方法是将传进来的实例进行验证和包装
// validateAndWrapHandlers preforms validation and wrapping for each input handler.
// It accepts an optional wrapper function to perform custom wrapping on handlers.
func validateAndWrapHandlers(handlers []Handler, wrappers ...func(Handler) Handler) []Handler {
var wrapper func(Handler) Handler
if len(wrappers) > 0 {
wrapper = wrappers[0]
}
wrappedHandlers := make([]Handler, len(handlers))
for i, h := range handlers {
h = validateAndWrapHandler(h)
if wrapper != nil && !inject.IsFastInvoker(h) {
h = wrapper(h)
}
wrappedHandlers[i] = h
}
return wrappedHandlers
}
validateAndWrapHandler 实现
// validateAndWrapHandler makes sure a handler is a callable function, it panics if not.
// When the handler is also potential to be any built-in inject.FastInvoker,
// it wraps the handler automatically to have some performance gain.
func validateAndWrapHandler(h Handler) Handler {
if reflect.TypeOf(h).Kind() != reflect.Func { //handler不是函数就直接panic
panic("Macaron handler must be a callable function")
}
if !inject.IsFastInvoker(h) { //如果不是fastinvoker 类型就进行下面的转换,如果下面类型也不是直接返回
switch v := h.(type) {
case func(*Context):
return ContextInvoker(v)
case func(*Context, *log.Logger):
return LoggerInvoker(v)
case func(http.ResponseWriter, *http.Request):
return handlerFuncInvoker(v)
case func(http.ResponseWriter, error):
return internalServerErrorInvoker(v)
}
}
return h
}
IsFastInvoker 判断
// IsFastInvoker check interface is FastInvoker
func IsFastInvoker(h interface{}) bool {
_, ok := h.(FastInvoker)
return ok
}
type FastInvoker interface {
// Invoke attempts to call the ordinary functions. If f is a function
// with the appropriate signature, f.Invoke([]interface{}) is a Call that calls f.
// Returns a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
Invoke([]interface{}) ([]reflect.Value, error)
}
如果接口实现了Invoke这个方法,那么他就是FastInvoker,下面再看看handler是怎么被包装的
ContextInvoker
// ContextInvoker is an inject.FastInvoker wrapper of func(ctx *Context).
type ContextInvoker func(ctx *Context)
// Invoke implements inject.FastInvoker which simplifies calls of `func(ctx *Context)` function.
func (invoke ContextInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
invoke(params[0].(*Context))
return nil, nil
}
handlerFuncInvoker
// handlerFuncInvoker is an inject.FastInvoker wrapper of func(http.ResponseWriter, *http.Request).
type handlerFuncInvoker func(http.ResponseWriter, *http.Request)
func (invoke handlerFuncInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
invoke(params[0].(http.ResponseWriter), params[1].(*http.Request))
return nil, nil
}
-
如果用户传进来的handler是这几种,那么转成相对应的函数,如果没有的话则直接返回handler
-
注意返回值是nil说明他们将来都只能作为中间件,没有返回值
中间件执行方式
func(resp http.ResponseWriter, req *http.Request, params Params) {
c := r.m.createContext(resp, req)
c.params = params
c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers))
c.handlers = append(c.handlers, r.m.handlers...)//添加全局默认handle
c.handlers = append(c.handlers, handlers...) //添加用户路由的handle
c.run() //执行中间件
}
context 结构
context.run()
func (ctx *Context) run() {
for ctx.index <= len(ctx.handlers) {
vals, err := ctx.Invoke(ctx.handler())
if err != nil {
panic(err)
}
ctx.index++
// if the handler returned something, write it to the http response
if len(vals) > 0 { //如果返回大于0,然后从返回值里面获取
ev := ctx.GetVal(reflect.TypeOf(ReturnHandler(nil)))
handleReturn := ev.Interface().(ReturnHandler) //获取默认的ReturnHandler
handleReturn(ctx, vals)
}
if ctx.Written() {
return
}
}
}
-
该方法跟所有web框架执行中间件的方法一样,循环遍历handler,每执行一个,索引+1
-
ctx.handler() 获取当前未执行索引的中间件,当中间件执行完毕后,执行action,action也是个handler,只是一个特殊的handler在中间件执行完毕后才会执行,一般是个业务 处理函数。
func (ctx *Context) handler() Handler {
if ctx.index < len(ctx.handlers) {
return ctx.handlers[ctx.index]
}
if ctx.index == len(ctx.handlers) {
return ctx.action
}
panic("invalid index for context handler")
}
action 设置方法
// Action sets the handler that will be called after all the middleware has been invoked.
// This is set to macaron.Router in a macaron.Classic().
func (m *Macaron) Action(handler Handler) {
handler = validateAndWrapHandler(handler)
m.action = handler
}
-
GetVal从一个类型和值对应得map里面取值,后面会讲讲这个injecter,框架会用Map方法把一些值映射进这个map里面,key 为反射获取的类型,value为反射获取的值,到时候根据值去取就行了
-
如果某个handler 会有向前端写数据的操作,那么ctx.Written()就会为true,然后返回
ReturnHandler
该方法是处理调用业务的返回值得,vals为调用的值
func defaultReturnHandler() ReturnHandler {
return func(ctx *Context, vals []reflect.Value) {
rv := ctx.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil)))
resp := rv.Interface().(http.ResponseWriter)//从injector 里面获取resp 的实例
var respVal reflect.Value
if len(vals) > 1 && vals[0].Kind() == reflect.Int {//如果vals 长度>1,并且第一个参数是int,那么这个就是状态码,调用resp.WriteHeader写入状态码
resp.WriteHeader(int(vals[0].Int()))
respVal = vals[1]
} else if len(vals) > 0 {
respVal = vals[0]
if isError(respVal) {
err := respVal.Interface().(error) //如果该第一个响应值是错误,直接响应服务器错误
if err != nil {
ctx.internalServerError(ctx, err)
}
return
} else if canDeref(respVal) {
if respVal.IsNil() {
return // Ignore nil error
}
}
}
if canDeref(respVal) {
respVal = respVal.Elem()
}
if isByteSlice(respVal) {
_, _ = resp.Write(respVal.Bytes())
} else {
_, _ = resp.Write([]byte(respVal.String()))
}
}
}
-
先获取响应值,看第一个值是不是int类型,如果是,写入这个值作为状态码,不是走下面分支
-
如果第一个值是error,直接响应服务器错误,internalServerError是个回调可以自己设置
internalServerError func(*Context, error)
-
如果是指针或者是接口,则获取respVal的值
-
最后判断是不是字节切片,如果是直接响应,如果不是则获取字符串,响应
internalServerError 结构
// InternalServerError configurates handler which is called when route handler returns
// error. If it is not set, default handler is used.
// Be sure to set 500 response code in your handler.
func (r *Router) InternalServerError(handlers ...Handler) {
handlers = validateAndWrapHandlers(handlers)
r.internalServerError = func(c *Context, err error) {
c.index = 0
c.handlers = handlers
c.Map(err)
c.run()
}
}
context.Next()
中间件的精髓就在这里
// Next runs the next handler in the context chain
func (ctx *Context) Next() {
ctx.index++
ctx.run()
}
举个例子,如果这样写一个中间件,那肯定是按顺序执行
func main() {
m := macaron.Classic()
m.Get("/", func(ctx *macaron.Context) {
fmt.Println("middleWare1")
}, func() string {
fmt.Println("hello1")
return "Hello world!"
})
m.Run()
}
请求 / 时,打印结果
middleWare1
hello1
如果加个next了,相当于递归调用,套娃执行
func main() {
m := macaron.Classic()
m.Get("/", func(ctx *macaron.Context) {
fmt.Println("middleWare1")
ctx.Next()
fmt.Println("middleWare2")
}, func() string {
fmt.Println("hello1")
return "Hello world!"
})
m.Run()
}
最后打印结果
middleWare1
hello1
middleWare2
画个图描述执行过程
当中间件调next就会这样按照图中序号套娃执行,在实际中间件应用中,如果想让其他中间件先执行,在后面再执行代码,那么就得调用context.Next进行执行,比如说计算业务代码的耗时等等。
举个例子,计算耗时的中间件
func Logger() macaron.Handler {
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
start := time.Now()
c.Data["perfmon.start"] = start
rw := res.(macaron.ResponseWriter)
c.Next()
timeTakenMs := time.Since(start) / time.Millisecond
}
ctx.Invoke
接下来来看看执行中间件的函数
context 是没有这个函数,他继承自inject.Injector
// Context represents the runtime context of current request of Macaron instance.
// It is the integration of most frequently used middlewares and helper methods.
type Context struct {
inject.Injector
handlers []Handler
action Handler
index int
*Router
Req Request
Resp ResponseWriter
params Params
Render
Locale
Data map[string]interface{}
}
当创建context的时候,被赋值为inject.New()
func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Context {
c := &Context{
Injector: inject.New(),
handlers: m.handlers,
action: m.action,
index: 0,
Router: m.Router,
Req: Request{req},
Resp: NewResponseWriter(req.Method, rw),
Render: &DummyRender{rw},
Data: make(map[string]interface{}),
}
c.SetParent(m)
c.Map(c) //将c 映射进去就是map[reflect(c.type)]=refelct(c.value)
c.MapTo(c.Resp, (*http.ResponseWriter)(nil))//将http.ResponseWriter类型的值映射换成自己的resp,到时候查找http.ResponseWriter类型的时候,会把自己的resp 传进去
c.Map(req)//将请求映射进去
return c
}
Injector
创建Injector
// New returns a new Injector.
func New() Injector {
return &injector{
values: make(map[reflect.Type]reflect.Value),
}
}
调用hanlder 的invoke 函数
Invoke
// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type.
// Returns a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
// It panics if f is not a function
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
t := reflect.TypeOf(f)
switch v := f.(type) {
case FastInvoker:
return inj.fastInvoke(v, t, t.NumIn())
default:
return inj.callInvoke(f, t, t.NumIn())
}
}
-
先获取handler的类型,如果是前面处理过的类型,就是context一类的,调用fastInvoke,如果都不是调用默认的callInvoke
fastInvoke
func (inj *injector) fastInvoke(f FastInvoker, t reflect.Type, numIn int) ([]reflect.Value, error) {
var in []interface{}
if numIn > 0 {
in = make([]interface{}, numIn) // Panic if t is not kind of Func
var argType reflect.Type
var val reflect.Value
for i := 0; i < numIn; i++ {
argType = t.In(i)
val = inj.GetVal(argType)//遍历传入参数,从map 里面找参数类型对应的值,然后给参数赋值
if !val.IsValid() {
return nil, fmt.Errorf("Value not found for type %v", argType)
}
in[i] = val.Interface()
}
}
return f.Invoke(in)
}
-
直接调用f.Invoke赋值,获取参数,然后调用f.Invoke进行函数调用,就是注册时候的ContextInvoker一类的方法
callInvoke
// callInvoke reflect.Value.Call
func (inj *injector) callInvoke(f interface{}, t reflect.Type, numIn int) ([]reflect.Value, error) {
var in []reflect.Value
if numIn > 0 {
in = make([]reflect.Value, numIn)
var argType reflect.Type
var val reflect.Value
for i := 0; i < numIn; i++ { //遍历传入参数,从map 里面找参数类型对应的值,然后给参数赋值
argType = t.In(i)
val = inj.GetVal(argType)
if !val.IsValid() {
return nil, fmt.Errorf("Value not found for type %v", argType)
}
in[i] = val
}
}
return reflect.ValueOf(f).Call(in), nil //反射调用handler,将获取的值作为参数传进去
}
-
遍历handler,如果handler的参数>0,然后遍历参数,从map 里面取出该类型的值,前提是要通过Map 方法映射进去,然后将该参数赋值,最后通过反射调用handler,将获得值传进去,这就能解释为什么,框架的中间件可以有很多种类型,比较灵活了
Map
map 负责将值的类型和值对应起来
// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
// It returns the TypeMapper registered in.
func (i *injector) Map(val interface{}) TypeMapper {
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
return i
}
下面举个例子介绍map方法怎么使用,下面的例子将T1 类型的值映射进去,在中间件里面写上func(t1*T1)形式就可以获取值,有点依赖注入的味道
type T1 int
func main() {
m := macaron.Classic()
var t T1=9999
m.Map(&t)
m.Get("/hello", func(t1*T1) {
fmt.Println(*t1) //打印9999
}, myHandler)
log.Println("Server is running...")
log.Println(http.ListenAndServe("0.0.0.0:5000", m))
}
Apply
该方法将结构的字段映射进去,如果结构体后面tag为inject
// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'.
// Returns an error if the injection fails.
func (inj *injector) Apply(val interface{}) error {
v := reflect.ValueOf(val)
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil // Should not panic here ?
}
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
structField := t.Field(i)
if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
ft := f.Type()
v := inj.GetVal(ft)
if !v.IsValid() {
return fmt.Errorf("Value not found for type %v", ft)
}
f.Set(v)
}
}
return nil
}
举个例子验证下apply 的应用
type Test struct {
T * macaron.Context
T1 * T1 `inject:"xx"`
}
type T1 int
func main() {
m := macaron.Classic()
var t T1=9999
m.Map(&t)
var t2 =&Test{}
err:=m.Apply(t2)
if err!=nil{
panic(err)
}
fmt.Println(*t2.T1)
m.Get("/hello", func(ctx * macaron.Context) {
}, myHandler)
log.Println("Server is running...")
log.Println(http.ListenAndServe("0.0.0.0:5000", m))
}
func myHandler(ctx *macaron.Context) string {
return "the request path is: " + ctx.Req.RequestURI
}
-
apply 将结构体放进去,如果结构体字段被打tag:inject,那么结构体这个字段将会通过f.Set(v)被赋上值。在后面grafana应用举例,我会讲解怎么在项目中应用这个函数。