You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

3.4 KiB

中间件声明 概述 ​ 在 go-zero 中,我们通过 api 语言来声明 HTTP 服务,然后通过 goctl 生成 HTTP 服务代码,在之前我们系统性的介绍了 API 规范。

在 HTTP 开发中,中间件是非常常见的需求,比如我们需要对请求进行鉴权,或者对请求进行日志记录,这些都是非常常见的需求。

中间件声明 ​ 假设我们有一个用户服务,我们需要将 user-agent 信息存入到 context 信息中,然后在 logic 层根据 user-agent 做业务处理,我们可以通过 api 语言来声明中间件, 在 api 语言中,我们可以通过 middleware 关键字来声明中间件,中间件的声明格式如下:

syntax = "v1"

type UserInfoRequest { Id int64 path:"id" } type UserInfoResponse { Id int64 json:"id" Name string json:"name" Age int32 json:"age" }

@server( // 通过 middileware 关键字声明中间件,多个中间件以英文逗号分割,如 UserAgentMiddleware,LogMiddleware middleware: UserAgentMiddleware ) service user { @handler userinfo get /user/info/:id (UserInfoRequest) returns (UserInfoResponse) } 在上面的例子中,我们声明了一个中间件 UserAgentMiddleware,然后在 @server 中通过 middileware 关键字来声明中间件。 我们来看一下生成的中间件代码:

目录结构

. ├── etc │ └── user.yaml ├── internal │ ├── config │ │ └── config.go │ ├── handler │ │ ├── routes.go │ │ └── userinfohandler.go │ ├── logic │ │ └── userinfologic.go │ ├── middleware # 中间件目录 │ │ └── useragentmiddleware.go │ ├── svc │ │ └── servicecontext.go │ └── types │ └── types.go ├── user.api └── user.go

8 directories, 10 files 中间件代码(未填充逻辑)

useragentmiddleware.go servicecontext.go routes.go package middleware

import "net/http"

type UserAgentMiddleware struct { }

func NewUserAgentMiddleware() *UserAgentMiddleware { return &UserAgentMiddleware{} }

func (m *UserAgentMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // TODO generate middleware implement function, delete after code implementation

    // Passthrough to next handler if need
    next(w, r)
}

} 你可以看到,中间件的代码是通过 goctl 自动生成的,中间件的代码是一个结构体,结构体中有一个 Handle 方法,这个方法是中间件的核心方法,这个方法接收一个 http.HandlerFunc 类型的参数,然后返回一个 http.HandlerFunc 类型的参数,这个方法的作用是对请求进行处理,然后将请求传递给下一个中间件或者 handler。

你可以在 Handle 方法中对请求进行处理,比如鉴权,日志记录等等,然后将请求传递给下一个中间件或者 handler。

如上需求例子,我们可以在中间件中将 header 中的 User-Agent 信息存到 context 中,中间件实现如下:

package middleware

import ( "context" "net/http" )

type UserAgentMiddleware struct { }

func NewUserAgentMiddleware() *UserAgentMiddleware { return &UserAgentMiddleware{} }

func (m *UserAgentMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { val := r.Header.Get("User-Agent") reqCtx := r.Context() ctx := context.WithValue(reqCtx, "User-Agent", val) newReq := r.WithContext(ctx) next(w, newReq) } }