中间件使用

    在go-zero中,中间件可以分为路由中间件和全局中间件,路由中间件是指某一些特定路由需要实现中间件逻辑,其和jwt类似,没有放在下的路由不会使用中间件功能, 而全局中间件的服务范围则是整个服务。

    中间件使用

    这里以search服务为例来演示中间件的使用

      1. type SearchReq struct {}
      2. type SearchReply struct {}
      3. @server(
      4. jwt: Auth
      5. middleware: Example // 路由中间件声明
      6. )
      7. service search-api {
      8. @handler search
      9. get /search/do (SearchReq) returns (SearchReply)
      10. }
    • 重新生成api代码
      1. $ goctl api go -api search.api -dir .
      1. etc/search-api.yaml exists, ignored generation
      2. internal/config/config.go exists, ignored generation
      3. search.go exists, ignored generation
      4. internal/svc/servicecontext.go exists, ignored generation
      5. internal/handler/searchhandler.go exists, ignored generation
      6. internal/handler/pinghandler.go exists, ignored generation
      7. internal/logic/searchlogic.go exists, ignored generation
      8. internal/logic/pinglogic.go exists, ignored generation
      9. Done.
      生成完后会在internal目录下多一个middleware的目录,这里即中间件文件,后续中间件的实现逻辑也在这里编写。
    • 完善资源依赖ServiceContext

      1. type ServiceContext struct {
      2. Config config.Config
      3. Example rest.Middleware
      4. }
      5. func NewServiceContext(c config.Config) *ServiceContext {
      6. Config: c,
      7. Example: middleware.NewExampleMiddleware().Handle,
      8. }
      9. }
    • 编写中间件逻辑 这里仅添加一行日志,内容example middle,如果服务运行输出example middle则代表中间件使用起来了。

      1. $ vim service/search/api/internal/middleware/examplemiddleware.go
      1. package middleware
      2. import "net/http"
      3. type ExampleMiddleware struct {
      4. }
      5. func NewExampleMiddleware() *ExampleMiddleware {
      6. return &ExampleMiddleware{}
      7. }
      8. func (m *ExampleMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
      9. return func(w http.ResponseWriter, r *http.Request) {
      10. // TODO generate middleware implement function, delete after code implementation
      11. // Passthrough to next handler if need
      12. next(w, r)
      13. }
      14. }
    • 启动服务验证
    1. func main() {
    2. flag.Parse()
    3. var c config.Config
    4. conf.MustLoad(*configFile, &c)
    5. ctx := svc.NewServiceContext(c)
    6. server := rest.MustNewServer(c.RestConf)
    7. defer server.Stop()
    8. server.Use(func(next http.HandlerFunc) http.HandlerFunc {
    9. return func(w http.ResponseWriter, r *http.Request) {
    10. logx.Info("global middleware")
    11. next(w, r)
    12. }
    13. })
    14. handler.RegisterHandlers(server, ctx)
    15. fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
    16. server.Start()
    17. }
    1. {"@timestamp":"2021-02-09T11:50:15.388+08","level":"info","content":"global middleware"}

    通过闭包的方式把其它服务传递给中间件,示例如下:

    1. // 模拟的其它服务
    2. type AnotherService struct{}
    3. func (s *AnotherService) GetToken() string {
    4. return stringx.Rand()
    5. }
    6. // 常规中间件
    7. func middleware(next http.HandlerFunc) http.HandlerFunc {
    8. return func(w http.ResponseWriter, r *http.Request) {
    9. w.Header().Add("X-Middleware", "static-middleware")
    10. next(w, r)
    11. }
    12. }
    13. // 调用其它服务的中间件
    14. func middlewareWithAnotherService(s *AnotherService) rest.Middleware {
    15. return func(next http.HandlerFunc) http.HandlerFunc {
    16. return func(w http.ResponseWriter, r *http.Request) {
    17. w.Header().Add("X-Middleware", s.GetToken())
    18. next(w, r)
    19. }
    20. }

    完整代码参考: