Go Fiber 框架系列:中间件

时间:2022-09-24 18:26:42

Go Fiber 框架系列:中间件

大家好,我是 polarisxu。

Middleware(中间件) 是一个 Web 框架重要的组成部分,通过这种模式,可以方便的扩展框架的功能。目前 Go Web 框架都提供了 Middleware 的功能,也有众多可用的 Middleware。

Fiber 也是如此,官方提供了众多的 Middleware,方便用户直接使用。本文先看看 Fiber 中 Middleware 的定义,然后介绍 Fiber 中的几个 Middleware,最后自己实现一个 Middleware。

Fiber 文档中关于 Middleware 的说明:中间件是在 HTTP 请求周期中链接的函数,它可以访问用于执行特定操作(例如,记录每个请求或启用 CORS)的上下文。

01 Middleware 长什么样

设计用于更改请求或响应的函数称为中间件函数。Next 是 Fiber 路由器函数,当它被调用时,执行与当前路由匹配的下一个函数。

可见,中间件其实和 Handler 是一样的,只是用途有区别。或者说至少签名是一样的,这样才能更好的形成一个链。

因此,Fiber 中的中间件签名如下:

  1. func(ctx*fiber.Ctx)error

Fiber 没有专门定义中间件类型。

此外,从 fiber.App.Use 方法也可以看到,中间件和普通的 Handler 并无本质不同。

  1. //Useregistersamiddlewareroutethatwillmatchrequests
  2. //withtheprovidedprefix(whichisoptionalanddefaultsto"/").
  3. //
  4. //app.Use(func(c*fiber.Ctx)error{
  5. //returnc.Next()
  6. //})
  7. //app.Use("/api",func(c*fiber.Ctx)error{
  8. //returnc.Next()
  9. //})
  10. //app.Use("/api",handler,func(c*fiber.Ctx)error{
  11. //returnc.Next()
  12. //})
  13. //
  14. //ThismethodwillmatchallHTTPverbs:GET,POST,PUT,HEADetc...
  15. func(app*App)Use(args...interface{})Router{
  16. varprefixstring
  17. varhandlers[]Handler
  18.  
  19. fori:=0;i(args);i++{
  20. switcharg:=args[i].(type){
  21. casestring:
  22. prefix=arg
  23. caseHandler:
  24. handlers=append(handlers,arg)
  25. default:
  26. panic(fmt.Sprintf("use:invalidhandler%v\n",reflect.TypeOf(arg)))
  27. }
  28. }
  29. app.register(methodUse,prefix,handlers...)
  30. returnapp
  31. }

而 fiber.Handler 类型只是 func(*fiber.Ctx) error 的别名:

  1. //HandlerdefinesafunctiontoserveHTTPrequests.
  2. typeHandler=func(*Ctx)error

这点上,Gin 框架和 Fiber 是类似的。不过,有一些框架,比如 Echo,专门定义了中间件类型。但不管怎么样,中间件的本质和普通路由 Handler 是类似的。

02 Fiber 内置的中间件

所有内置的中间件可以在 fiber 项目的 middleware 子包找到,这些中间件对应的文档在这里:https://docs.gofiber.io/api/middleware。

以 Recover 中间件为例,看看官方中间件的实现方法,我们自己的中间件可以参照实现。

1)签名

  1. funcNew(config...Config)fiber.Handler

上文说了,中间件就是一个 Handler,因此这里 New 函数返回 fiber.Handler,这就中间件。

至于 New 函数的参数不做任何要求,只需要最终返回 fiber.Handler 即可。

2)配置

一个好的中间件,或通用的中间件,一般都会有配置,让中间件更灵活、更强大。看看 Recover 的配置定义:

  1. //Configdefinestheconfigformiddleware.
  2. typeConfigstruct{
  3. //Nextdefinesafunctiontoskipthismiddlewarewhenreturnedtrue.
  4. //
  5. //Optional.Default:nil
  6. Nextfunc(c*fiber.Ctx)bool
  7.  
  8. //EnableStackTraceenableshandlingstacktrace
  9. //
  10. //Optional.Default:false
  11. EnableStackTracebool
  12.  
  13. //StackTraceHandlerdefinesafunctiontohandlestacktrace
  14. //
  15. //Optional.Default:defaultStackTraceHandler
  16. StackTraceHandlerfunc(einterface{})
  17. }

具体配置是什么样的,需要根据中间件的功能来定义。

不过,配置中 Next 这个行为,很多中间件都可以有。

3)默认配置

一般的,会提供一个默认配置,方便使用。而且,大部分时候,使用默认配置即可。Recover 的默认配置如下:

  1. varConfigDefault=Config{
  2. Next:nil,
  3. EnableStackTrace:false,
  4. StackTraceHandler:defaultStackTraceHandler,
  5. }

如果这样调用 recover.New() ,会默认使用上面的默认配置。

最后看看 New 函数的代码:

  1. //Newcreatesanewmiddlewarehandler
  2. funcNew(config...Config)fiber.Handler{
  3. //Setdefaultconfig
  4. cfg:=configDefault(config...)
  5.  
  6. //Returnnewhandler
  7. returnfunc(c*fiber.Ctx)(errerror){
  8. //Don'texecutemiddlewareifNextreturnstrue
  9. ifcfg.Next!=nil&&cfg.Next(c){
  10. returnc.Next()
  11. }
  12.  
  13. //Catchpanics
  14. deferfunc(){
  15. ifr:=recover();r!=nil{
  16. ifcfg.EnableStackTrace{
  17. cfg.StackTraceHandler(r)
  18. }
  19.  
  20. varokbool
  21. iferr,ok=r.(error);!ok{
  22. //Seterrorthatwillcalltheglobalerrorhandler
  23. err=fmt.Errorf("%v",r)
  24. }
  25. }
  26. }()
  27.  
  28. //Returnerrifexist,elsemovetonexthandler
  29. returnc.Next()
  30. }
  31. }

以上就是一个 Fiber 标准中间件的写法。

具体使用时就是:app.Use(recover.New())。

当然,如果只是自己项目使用,可以不用写配置。

03 实现一个简单的中间件

通过 Recover 学习到了中间件的标准写法,如果中间件只在自己项目使用,不需要灵活性,完全可以采用简单的写法。

  1. funcSecurity(ctx*fiber.Ctx)error{
  2. ctx.Set("X-XSS-Protection","1;mode=block")
  3. ctx.Set("X-Content-Type-Options","nosniff")
  4. ctx.Set("X-Download-Options","noopen")
  5. ctx.Set("Strict-Transport-Security","max-age=5184000")
  6. ctx.Set("X-Frame-Options","SAMEORIGIN")
  7. ctx.Set("X-DNS-Prefetch-Control","off")
  8.  
  9. //执行下一个Handler
  10. returnctx.Next()
  11. }

这其实也是一个 Handler,对吧。无非最后调用的是 ctx.Next,而不是 ctx.JSON 之类的。

使用时这样:

  1. app:=fiber.New()
  2. app.Use(Security)

只要理解中间件的机制,不需要拘泥于具体形式,可以灵活变换中间件的写法。

04 总结

本文讲解了什么是中间件,Fiber 中间件长什么样以及对内置中间件 Recover 的学习,最后自己实现一个简单的中间件。掌握了 Fiber 的中间件,相信对其他 Go Web 框架的中间件的学习也就不难了,因为都差不多。

原文链接:https://mp.weixin.qq.com/s/NL6MYQpvVOyJREiVX_DAgQ