一、控制器(controller)

控制器是Iris支持的重要特性之一,他能够非常清晰、方便的去定义和管理接口。 Iris controller 的设计思想是约定优于配置,只要按照他Iris的约定规则来编写代码即可很简单地完成一个controller,下面我们通过一个实例来了解一下,代码如下:

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/mvc"

    "github.com/kataras/iris/middleware/logger"
    "github.com/kataras/iris/middleware/recover"
)

func main() {
    app := iris.New()
    app.Logger().SetLevel("debug")
    app.Use(recover.New())
    app.Use(logger.New())

    mvc.Configure(app.Party("/root"), func(mvcApp *mvc.Application) {
        mvcApp.Handle(new(MyController))
    })

    _ = app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

type MyController struct {
    Ctx iris.Context
}

// GET: http://localhost:8080/root
func (m *MyController) Get() string {
    return "Hey"
}

// GET: http://localhost:8080/root/123
func (m *MyController) GetBy(id int64) interface{} {
    return map[string]interface{}{"id": id}
}

// GET: http://localhost:8080/root/hello/world
func (m *MyController) GetHelloWorld() interface{} {
    return map[string]string{"message": "Hello world!"}
}

// GET: http://localhost:8080/root/hello
func (m *MyController) GetHello() interface{} {
    return map[string]string{"message": "Hello Iris!"}
}

// Any: http://localhost:8080/root/test
func (m *MyController) AnyTest() {
    _, _ = m.Ctx.HTML("<h1>test</h1>")
}

上面代码中我们定义了一个 controller 叫做 MyController,在该MyController中定义了几个接口,这些接口的访问路径都写在注释中了。通过总结这些函数的访问路径,我们可以简单的得到以下结论:

  • controller的路由规则为:HttpMethod + FuncName(函数名会根据驼峰命名法进行分割),其中HttpMethod限定该接口的请求类型,FuncName限定接口的路径;
  • controller中函数名以Any开头表示该接口不限定请求类型,任何类型的请求都可以正常访问。
  • controller中函数名称结尾带By关键字的,接受一个输入参数,例如GetBy

方法名的前缀为HttpMethod,用来定义当前接口的请求类型,你还可以使用更多的 HttpMethod,例如:

func (m *MyController) Post() {}
func (m *MyController) Put() {}
func (m *MyController) Delete() {}
func (m *MyController) Connect() {}
func (m *MyController) Head() {}
func (m *MyController) Patch() {}
func (m *MyController) Options() {}
func (m *MyController) Trace() {}

func (m *MyController) All() {}
// OR
func (m *MyController) Any() {}

虽然controller中根据命名规则来定义访问路径非常的简单好用,能满足我们绝大部分的日常使用需求,但是一些复杂的路径规则还是无法适用,iris很人性化的考虑到了这一点,所以它提出了一个BeforeActivation概念。

BeforeActivation会在controller适配之前调用,在BeforeActivation中你可以自定义路由,我们通过下面的例子来了解它的使用方式:

func (this *MyController) BeforeActivation(b mvc.BeforeActivation) {
    // 1-> Method
    // 2-> Path
    // 3-> The controller's function name to be parsed as handler
    // 4-> Any handlers that should run before the MyCustomHandler
    b.Handle("GET", "/something/{id:long}", "MyCustomHandler")
}

// GET: http://localhost:8080/root/something/{id:long}
func (m *MyController) MyCustomHandler(id int64) string {
    return "MyCustomHandler says Hey"
}

那么这个时候我们就为MyController新增了一个接口,通过路径/something/{id:long}就能够访问到该接口了。

二、中间件(middleware)

中间件可以在controller执行前或者执行后执行某个操作。如果你熟悉 Java 的话,就很容易理解中间件,我们可以将它看做是 Java 中的ServletFilter

利用中间件我们可以将一些通用的操作全部抽象到中间件中,而不必将这些通用的代码放到每个controller中,以此来减少重复代码和解耦代码。例如我们列出以下几个中间件常用的场景:

  • 权限控制
  • 接口签名
  • 访问统计

下面我们使用中间件实现一个接口访问次数统计功能,通过该 demo 来了解中间件的使用方式:

package main

import (
    "fmt"
    "strconv"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/mvc"

    "github.com/kataras/iris/middleware/logger"
    "github.com/kataras/iris/middleware/recover"
)

func main() {
    app := iris.New()
    app.Logger().SetLevel("debug")
    app.Use(recover.New())
    app.Use(logger.New())

    count := 0

    mvc.Configure(app.Party("/root"), func(mvcApp *mvc.Application) {
        mvcApp.Router.Use(func(context context.Context) {
            if context.Path() == "/root/test" {
                count++
                fmt.Println("/root/test 请求次数:" + strconv.Itoa(count))
            }
            context.Next() // 加上他让Web进程继续往下执行,否则不会执行controller方法
        })
        mvcApp.Handle(new(MyController))
    })

    _ = app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

type MyController struct {
    Ctx iris.Context
}

// Any: http://localhost:8080/root/test
func (m *MyController) AnyTest() {
    _, _ = m.Ctx.HTML("<h1>test</h1>")
}

执行之后,当每次请求/root/test接口的时候控制台输出的数量都会+1,注意我们在中间件函数的最后需要加上context.Next(),该函数会告诉 iris 继续执行下面的 controller,否则代码不会执行到 controller。