Iris 框架解析之三

2,527 阅读4分钟
原文链接: lizetong.me

前言

目前这个网站就是自己用iris新搭的,需求和功能也在一步一步的完善。前两篇已经发布快一个星期了,慢慢也收到了一些反馈。其中就有说到iris作者之前的一些种种行为,而使大家对iris库略有偏见。但对于我来说,一个技术宅,只关心技术本身的价值,而不会去关心作者的是非。

接下来进入主题,今天解析Middleware和Router部分。

Middleware的用途

顾名思义,Middleware就是中间件。很直观点,可以理解为是一座桥、一扇门、一根网线之类,具有连接、传输作用的媒介。 在iris中Middleware可以拆解一个复杂的过程为多个步骤。 在此我解析一下它的逻辑和实现,至于应用场景,可以针对平时工作中的业务逻辑而定。

Middleware逻辑解析

来看一下作者给出的例子(为了方便说明,分别给注释加了编号)

//1 First mount static files
iris.StaticWeb("/assets", "./public/assets")

//2 Then declare which middleware to use (custom or not)
iris.Use(myMiddleware{})
iris.UseFunc(func(ctx *iris.Context){})

//3 declare any finish middleware/ runs always at the end of the request using .Done/.DoneFunc
iris.DoneFunc(executeLast)

//4 Now declare routes
iris.Get("/myroute", func(ctx *iris.Context) {
    // do stuff
})
iris.Get("/secondroute", myMiddlewareFunc, myRouteHandlerfunc)

//5 Now run the server
iris.Listen(":8080")


//6 executeLast func middleware
func executeLast(ctx *iris.Context){
    println("before close the http request")
}

//7 myMiddleware will be like that
type myMiddleware struct {
  // your 'stateless' fields here
}
//8
func (m myMiddleware) Serve(ctx *iris.Context){
  // ...
}

要想完全弄明白Middleware,这段代码就够了,下来我们一起来看一下里面的点

  • 从注释2一直到8,都在说明不同的用法。
  • 首先说一个小细节iris.Useiris.UseFunc分表示使用struct还是函数
  • 噢,对了,忘说了,Middleware既可以是一个struct也可以是一个函数,但分别有自己的格式规则。

struct格式

要定义struct格式的Middleware,需要实现Serve方法。

看到这是不是有点眼熟,没错,这个方法就是Handler中的func (m myMiddleware) Serve(ctx *iris.Context)

其实这个格式就是前面讲过的Handler。看注释的7和8,是不是和前面的Handler实现一模一样。

然而用iris.Use(myMiddleware{})来注册struct会在路由Router之前执行。

Func格式

上面讲strut格式的时候提到了Handler,那Func格式也是需要实现Handler接口的server方法的。

看上面的注释2和3的iris.UseFunciris.DoneFunc直接调用了Context参数的函数,并没有实现Handler,其实在这个两个方法的源码里面已经实现了

文件:iris.go
// UseFunc registers HandlerFunc middleware
// returns itself
func (api *muxAPI) UseFunc(handlersFn ...HandlerFunc) MuxAPI {
    return api.Use(convertToHandlers(handlersFn)...)
}

文件:http.go
// convertToHandlers just make []HandlerFunc to []Handler, although HandlerFunc and Handler are the same
// we need this on some cases we explicit want a interface Handler, it is useless for users.
func convertToHandlers(handlersFn []HandlerFunc) []Handler {
    hlen := len(handlersFn)
    mlist := make([]Handler, hlen)
    for i := 0; i < hlen; i++ {
        mlist[i] = Handler(handlersFn[i])
    }
    return mlist
}

看上面源码就能清楚的看到最后实现Handler接口,iris.DoneFunc在源码里也一样。

特别提示,而这两个函数最大的区别就是:一个在Router之前执行,一个在所有Router之后执行

Middleware用法

看代码中的这一句

iris.Get("/secondroute", myMiddlewareFunc, myRouteHandlerfunc)

这里分别一次调用了两个函数,他们的依次执行。但是又有一个点就是:在这里调用的函数是不是就不需要实现Handler了,其实不是,同样也是要实现的。具体怎么实现,我们来看一下:

func myMiddlewareFunc(ctx *iris.Context){
    ctx.Writef("1. This is the first middleware\n")
    ctx.Next()
}

func myRouteHandlerfunc(ctx *iris.Context) {
    ctx.Writef("2. This is the second middleware \n")
    ctx.Next()
}

看到里面ctx.Next()方法了吧!奥秘就在这里,我们继续看

// Next calls all the next handler from the middleware stack, it used inside a middleware
func (ctx *Context) Next() {
    //set position to the next
    ctx.Pos++
    midLen := len(ctx.Middleware)
    //run the next
    if ctx.Pos < midLen {
        ctx.Middleware[ctx.Pos].Serve(ctx)
    }
}

看到了吧,同样在Next()方法里实现了Server方法。

但同时,Next()还有自己的含义,就是是否还执行后面的Middleware方法(例如上面的例子,myMiddlewareFunc中没有调用Next(),就不会执行myRouteHandlerfunc)

总结

所以,其实Middleware就是Handler,只是做了不同的实现逻辑,因此可以满足不同的业务逻辑 通过Next()方法串行的将多个Middleware连接起来,依次执行


Router

至于Router,iris的路由解析还是比较弱的。这其实也性能上快的一种方式吧。 如果路由解析很强大,必然要支持正则,这样会降低一些性能。

  • 由于很简单,就只贴一段代码,大家看看吧

其中包含了几种方式:GET, POST, PUT, DELETE, HEAD, PATCH & OPTIONS

package main

import "github.com/kataras/iris"

func main() {
    // declare the routes
    iris.Get("/home", testGet)
    iris.Post("/login", testPost)
    iris.Put("/add", testPut)
    iris.Delete("/remove", testDelete)
    iris.Head("/testHead", testHead)
    iris.Patch("/testPatch", testPatch)
    iris.Options("/testOptions", testOptions)
    iris.Connect("/testConnect", testConnect)
    iris.Trace("/testTrace", testTrace)

    // start the server
    iris.Listen(":8080")
}

func testGet(ctx *iris.Context) {
    //...
}
func testPost(ctx *iris.Context) {
    //...
}

讲的比较直观,如果你有什么问题疑惑欢迎留言,看到第一时间答复


**版权声明:本文为博主原创文章,转载请注明出处。**