Wego Web Framework | GitHub 开发文档 开发社区
快速入门
Web模块
ORM模块
其他模块

拦截器与过滤器

拦截器

拦截器是一个action(处理器函数)之前或之后被调用的函数。拦截器能够用于以下常见问题:

函数拦截器

wego中有两种形式的拦截器,一种是函数型拦截器,函数型的形式与一般的处理器函数相同。wego中有以下三种拦截器:

接下来的例子我们使用拦截器来验证用户登录状态,并使用cookie引擎来存储session数据。


func main() {
	web, err := wego.NewWeb()
	if err != nil{
		log.Error(err)
		return
	}

	//初始化session
	store := cache.NewCookieStore("demo", "1111")
	web.Session.Init(store)

	//设置BeforExec拦截器
	web.BeforExec(hookBefore)

	//路由注册
	web.GET("/login", login)
	web.GET("/index", index)

	err = web.Run(":8080")
	if err != nil {
		log.Error(err)
	}
}

上面的代码中我们使用了cookie引擎来存储session数据,并注册了两个处理器函数,login以及index。login处理器的定义如下:


func login(c *wego.WebContext)  {
	c.Session.Set("uid", 1)
	c.Session.Save()
	c.Redirect(302, "/index")
}

login函数处理器用于将用户登录信息写入session,并跳转到index页面


func hookBefore(c *wego.WebContext)  {
	id, err := c.Session.GetInt("uid")
	if err != nil || id < 0 {
		c.Redirect(302, "/login")
	}
	c.Data.Set("uid", id)
}

hookBefore就是一个拦截器,其形式与函数型处理器是相同的。在hookBefore中我们读取session中的数据,判断是否存在uid,若不存在则跳转到登录页面:/login


func index(c *wego.WebContext)  {
	id , _ := c.Data.GetInt64("uid")
	c.WriteTextF(200, "uid=%d", id)
}

接口拦截器

wego中的另外一种拦截器是接口拦截器。wego中定义了以下两种接口用于拦截HTTP请求:


type BeforeExecer interface {
	BeforeExec(ctx *WebContext)
}
type AfterExecer interface {
	AfterExec(ctx *WebContext)
}

一个struct若实现了BeforeExecer接口,则在执行action之前会先执行BeforeExec成员函数;同样若struct实现了AfterExecer接口,则在执行action之后会执行AfterExec成员函数。


func main() {
	web, err := wego.NewWeb()
	if err != nil{
		log.Error(err)
		return
	}

	//初始化session
	store := cache.NewCookieStore("demo", "1111")
	web.Session.Init(store)
    
    //路由注册
	web.GET("/login", (*LoginControl).Login)
	web.GET("/index", (*IndexControl).Index)

	err = web.Run(":8080")
	if err != nil {
		log.Error(err)
	}
}

上面的代码中注册了两个接口型路由器:(*LoginControl).Login,以及(*IndexControl).Index, 首先看看LoginControl的定义:


type LoginControl struct {
}
func (this *LoginControl) Login(c *wego.WebContext) {
	c.Session.Set("uid", 1)
	c.Session.Save()
	c.Redirect(302, "/index")
}

接下来是IndexControl的定义:


type IndexControl struct {
	BaseControl
}
func (this *IndexControl) Index(c *wego.WebContext) {
	c.WriteTextF(200, "uid=%d", this.GetUID(c))
}

在IndexControl中组合了BaseControl,因此IndexControl也继承了BaseControl的方法,通常将一些公用的功能添加到BaseControl中,例如:登陆验证。BaseControl的实现如下:


type BaseControl struct {
}
func (this *BaseControl) SetUID(c *wego.WebContext, uid int64) {
	c.Data.Set("uid", uid)
}
func (this *BaseControl) GetUID(c *wego.WebContext) int64{
	uid , _ := c.Data.GetInt64("uid")
	return uid
}
func (this *BaseControl) BeforeExec(c *wego.WebContext) {
	val, err := c.Session.GetInt("uid")
	if err != nil {
		c.Redirect(302, "/login")
	}
	this.SetUID(c, val)
}

在BaseControl的BeforeExec成员函数中读取session数据:uid,若不存在uid则跳转到/login页面。

拦截器的优先级

beforeRoute拦截器只能是全局拦截器,before_exec、after_exec可以是以下类型:


若同时设置了以上拦截器,则优先级为:
函数拦截器->接口拦截器->路由组拦截器->全局拦截器

过滤器

过滤器是wego框架的中间件,是一种可以拦截http请求-响应生命周期的特殊函数,在请求-响应生命周期中可以注册多个中间件,

每个中间件执行不同的功能,一个中间执行完再执行下一个中间件。

过滤器的使用

通过AddFilter设置全局过滤器或者是给路由组设置过滤器,下面是一个设置全局过滤器的例子:


func main() {
	web, err := wego.InitWeb("./app.conf")
	if err != nil{
		log.Error(err)
		return
	}

    //设置生成请求ID的过滤器
	web.AddFilter("GenRequestID", filters.GenRequestID())
	web.GET("/reqid", ShowHtml)

	err = web.Run(":8080")
	if err != nil {
		log.Error(err)
	}
}
func ShowHtml(c *wego.WebContext) {
	c.UseGzip(true).WriteHTML(200, "./content.html", nil)
}

自定义过滤器

通过下面一个例子,读者可以了解如何自定义一个过滤器中间件:


func genRequestID() string {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		return ""
	}
	sid := hex.EncodeToString(b)
	return sid
}

const keyRequestID = "X-Request-ID"
func GenRequestID() wego.HandlerFunc {
	return func(c *wego.WebContext) {
		rid :=c.Input.GetHeader(keyRequestID)
		if rid == "" {
			rid = genRequestID()
			c.Input.Header.Add(keyRequestID, rid)
		}
		c.SetHeader(keyRequestID, rid)
		c.Next()
	}
}

过滤器的优先级

过滤器可以是以下类型:


若同时设置了以上过滤器,则优先级为:
1)首先检查所属路由组存在过滤器, 若存在这使用当前路由组过滤器;
2)若不存在,则检查上级路由组是否有过滤器,若存在则使用上级路由组过滤器;
......
3)最后查看是否存在全局过滤器,若存在则使用全局过滤器