go-zero(八) 中间件的使用
go-zero(八) 中间件的使用
go-zero 中间件
一、中间件介绍
中间件(Middleware)是一个在请求和响应处理之间插入的程序或者函数,它可以用来处理、修改或者监控 HTTP 请求和响应的各个方面。
1.中间件的核心概念
请求拦截:中间件能够在请求到达目标处理器之前,对请求进行分析、修改或记录。
响应拦截:同样,中间件也可以在响应返回给客户端之前,对响应进行处理,例如添加 headers、压缩响应体、格式化响应数据等。
链式调用:多个中间件可以串联在一起,形成一个中间件链,依次处理请求和响应。
2.中间件的用途
中间件可以用于以下多个方面:
日志记录:记录 HTTP 请求和响应的详细信息,例如请求路径、方法、状态码等。这有助于进行审计和调试。
认证和授权:验证请求是否具有必要的权限,确保用户或系统的身份是否合法。这对于保护敏感接口尤其重要。
请求限流:控制访问速率,避免服务被恶意请求或流量洪水淹没。这可以提高系统的稳定性和可用性。
跨域资源共享 (CORS):处理浏览器的跨域请求。中间件可以在响应中添加适当的 CORS 头,允许来自不同源的请求。
错误处理:捕获处理过程中的错误(如 panic)并生成适当的 HTTP 响应。这样可以确保系统在错误情况下不会崩溃,并能够正常返回相应。
数据格式化:统一请求和响应的数据格式,例如将响应数据转换为 JSON 格式,或者对请求中的参数进行验证和转换。
国际化 (i18n):处理用户的语言偏好和内容的本地化,使应用能够支持多语言。
3.中间件的工作流程
一般来说,工作流程如下:
用户发起请求,请求到达 Web 服务器。
中间件链开始处理:
第一个中间件接收请求,进行相应的处理(如日志记录)。
控制权传递给下一个中间件。
这个过程可以一直持续,直到所有中间件处理完请求。
最终请求到达目标处理器,处理器生成响应。
响应同样会经过中间件链进行处理(如添加 headers)。
最终响应返回给用户。
二、go-zero内置中间件介绍
go-zero 提供了一系列内置的中间件, 之前我们使用的JWT鉴权就使用了内置的
鉴权管理中间件
帮助我们实现了自动验证Token。
在 go-zero 中内置了如下中间件:
鉴权管理中间件 AuthorizeHandler
熔断中间件 BreakerHandler
内容安全中间件 ContentSecurityHandler
解密中间件 CryptionHandler
压缩管理中间件 GunzipHandler
日志中间件 LogHandler
ContentLength 管理中间件 MaxBytesHandler
限流中间件 MaxConnsHandler
指标统计中间件 MetricHandler
普罗米修斯指标中间件 PrometheusHandler
panic 恢复中间件 RecoverHandler
负载监控中间件 SheddingHandler
超时中间件 TimeoutHandler
链路追踪中间件 TraceHandler
这些中间件的具体实现可以去看
github.com\zeromicro\go-zero@v1.7.3\rest\handler
目录的内容。
1. 开/关中间件
以上中间件
默认启用
, 如果想要关闭其中的中间件,我们可以通过配置文件来控制。
如果你看过
RestConf
的代码,就应该能看到,它里面包含了一个
Middlewares
中间件的配置结构。
RestConf struct {
service.ServiceConf
Host string `json:",default=0.0.0.0"`
Port int
/*
....
*/
//中间件配置相关的结构体
Middlewares MiddlewaresConf
// TraceIgnorePaths is paths blacklist for trace middleware.
}
我们可以看下它的具体内容,可以看到这个结构体主要用来控制,这些中间件是否启动,默认都是开启状态:
MiddlewaresConf struct {
Trace bool `json:",default=true"`
Log bool `json:",default=true"`
Prometheus bool `json:",default=true"`
MaxConns bool `json:",default=true"`
Breaker bool `json:",default=true"`
Shedding bool `json:",default=true"`
Timeout bool `json:",default=true"`
Recover bool `json:",default=true"`
Metrics bool `json:",default=true"`
MaxBytes bool `json:",default=true"`
Gunzip bool `json:",default=true"`
}
那么如何控制这些中间件是否关闭就很简单了,例如我想关闭
普罗米修斯指标中间件
,打开
yaml
文件:
Middlewares:
Prometheus: false #把值设置为false
关于内置中间件展示就介绍这么多,后面有机会给大家详细介绍下具体的使用方法。
三、自定义中间件
1.局部中间件
在 go-zero 中,我们通过 api 语言来声明 HTTP 服务,然后通过 goctl 生成 HTTP 服务代码。
type (
RegisterRequest {
//请求体定义了 Username 和Password 字段, 并且都设置了不能为空
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
}
RegisterResponse {
//响应体 定义类一个Message 用来返回结果
Message string `json:"message"`
}
)
type (
LoginRequest {
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
}
LoginResponse {
Token string `json:"token"`
}
)
@server (
group: user // 代表当前 service 代码块下的路由生成代码时都会被放到 user 目录下
prefix: /v1 //定义路由前缀为 "/v1"
middleware: TestMiddleware
)
在上面的例子中,我们声明了一个中间件
TestMiddleware
,然后在 @server 中通过
middileware
关键字来声明中间件。
需要说明的,我们这个中间件是局部中间件,仅对当前的
server
有效
使用以下命令更新代码:
goctl api go --api user.api --dir .
命令执行完后,会在项目中生成
middleware
文件夹,我们可以先看下
routes.go
文件,可以看到这路由前面帮我加了一个中间件
接下来我们打开
middleware
目录下的文件,我们简单的添加一个header信息,修改代码:
func (m *TestMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// TODO generate middleware implement function, delete after code implementation
//我们自定义一个header信息
w.Header().Set("xxxx", "aaaabb")
next(w, r)
}
}
然后把中间件注册到服务中,打开
servicecontext.go
文件:
type ServiceContext struct {
Config config.Config
UserModel model.UsersModel
UserRpc user.User
TestMiddleware rest.Middleware //定义中间件
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserModel: model.NewUsersModel(sqlx.NewMysql(c.MysqlDB.DbSource)),
UserRpc: user.NewUser(zrpc.MustNewClient(c.UserRpcConf)),
//初始化中间件
TestMiddleware Middleware: middleware.NewTestMiddleware Middleware().Handle,
}
}
运行项目测试
2. 全局中间件
下面我们演示下全局中间件
首先我们创建一个 Middleware 方法:
func GlobalMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logx.Info("全局中间件")
next(w, r)
}
}
然后将其注册到 go-zero 的 rest 中
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
server := rest.MustNewServer(c.RestConf)
defer server.Stop()
//使用Use 注册中间件
server.Use(middleware.GlobalMiddleware)
ctx := svc.NewServiceContext(c)
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}