go-zero(八) 中间件的使用

go zero 中间件的使用

一、中间件介绍

中间件(Middleware)是一个在请求和响应处理之间插入的程序或者函数,它可以用来处理、修改或者监控 HTTP 请求和响应的各个方面。中间件通常位于 web 服务器和应用逻辑之间,它们可以拦截请求和响应流,对其进行某种处理,然后决定是否将控制传递给下一个中间件或最终的处理程序。

1.中间件的核心概念

  1. 请求拦截:中间件能够在请求到达目标处理器之前,对请求进行分析、修改或记录。

  2. 响应拦截:同样,中间件也可以在响应返回给客户端之前,对响应进行处理,例如添加 headers、压缩响应体、格式化响应数据等。

  3. 链式调用:多个中间件可以串联在一起, 形成一个中间件链,依次处理请求和响应。

2.中间件的用途

中间件可以用于以下多个方面:

  1. 日志记录:记录 HTTP 请求和响应的详细信息,例如请求路径、方法、状态码等。这有助于进行审计和调试。
  2. 认证和授权:验证请求是否具有必要的权限,确保用户或系统的身份是否合法。这对于保护敏感接口尤其重要。
  3. 请求限流:控制访问速率,避免服务被恶意请求或流量洪水淹没。这可以提高系统的稳定性和可用性。
  4. 跨域资源共享 (CORS):处理浏览器的跨域请求。中间件可以在响应中添加适当的 CORS 头,允许来自不同源的请求。
  5. 错误处理:捕获处理过程中的错误(如 panic)并生成适当的 HTTP 响应。这样可以确保系统在错误情况下不会崩溃,并能够正常返回相应。
  6. 数据格式化:统一请求和响应的数据格式,例如将响应数据转换为 JSON 格式,或者对请求中的参数进行验证和转换。
  7. 国际化 (i18n):处理用户的语言偏好和内容的本地化,使应用能够支持多语言。

3.中间件的工作流程

一般来说,工作流程如下:

  1. 用户发起请求,请求到达 Web 服务器。
  2. 中间件链开始处理:
    • 第一个中间件接收请求,进行相应的处理(如日志记录)。
    • 控制权传递给下一个中间件。
    • 这个过程可以一直持续,直到所有中间件处理完请求。
  3. 最终请求到达目标处理器,处理器生成响应。
  4. 响应同样会经过中间件链进行处理(如添加 headers)。
  5. 最终响应返回给用户。

这种结构类似于"洋葱模型":请求像是从外到内穿过洋葱层,而响应则是从内到外穿出。
在这里插入图片描述

二、go zero内置中间件介绍

go zero 提供了一系列内置的中间件,以帮助开发者管理 HTTP 请求的不同方面。

还记得之前的jwt鉴权吗?那边我们只实现了token生成,但是并没有实现验证,但是go zero能够自动解析token,就是因为它内置了AuthorizeHandler(鉴权管理中间件)

1. 内置中间件一览

在 go zero 中内置了如下中间件:

中间件名称 功能描述 默认状态
AuthorizeHandler 身份验证与授权控制 启用
BreakerHandler 服务熔断,防止级联故障 启用
LogHandler 请求日志记录 启用
MetricHandler 服务指标统计 启用
PrometheusHandler Prometheus 监控指标收集 启用
RecoverHandler Panic 恢复,防止服务崩溃 启用
TimeoutHandler 请求超时控制 启用
TraceHandler 分布式链路追踪 启用
MaxConnsHandler 最大连接数限制 启用
SheddingHandler 负载均衡与请求分流 启用
GunzipHandler 响应压缩管理 启用
MaxBytesHandler 请求体大小限制 启用
ContentSecurityHandler 内容安全策略 启用
CryptionHandler 请求/响应加解密 启用

这些中间件的具体实现可以去看github.com\zeromicro\go [email protected]\rest\handler目录的内容。

2. 核心中间件详解

认证中间件 (AuthorizeHandler)

JWT 认证是 Go-Zero 中最常用的身份验证方式,由内置的 AuthorizeHandler 提供支持。

工作原理

  1. 验证请求头中的 Authorization 字段
  2. 解析 JWT Token 并验证有效性
  3. 将用户信息存入上下文,供后续处理器使用

源码解析

// Authorize 函数用于创建一个 HTTP 中间件,该中间件可对传入的 HTTP 请求进行身份验证。
// 它会从请求中解析 JWT(JSON Web Token),验证其有效性,并将 JWT 中的自定义声明添加到请求的上下文(context)中,供后续处理程序使用。
// 参数 secret 是用于验证 JWT 的密钥,为字符串类型。
// 参数 opts 是可变参数,类型为 AuthorizeOption,用于配置身份验证的选项。
// 函数返回一个 func(http.Handler) http.Handler 类型的函数,即一个 HTTP 中间件。
func Authorize(secret string, opts ...AuthorizeOption) func(http.Handler) http.Handler {
   
   
	// 定义一个 AuthorizeOptions 类型的变量 authOpts,用于存储身份验证的选项。
	var authOpts AuthorizeOptions
	// 遍历传入的选项 opts
	for _, opt := range opts {
   
   
		// 调用每个选项函数,将 authOpts 的指针传递给它们,以设置具体的选项。
		opt(&authOpts)
	}

	// 创建一个 token.TokenParser 类型的实例 parser,用于解析 JWT。
	parser := token.NewTokenParser()

	// 返回一个中间件函数,该函数接受一个 http.Handler 类型的参数 next,表示下一个处理程序。
	return func(next http.Handler) http.Handler {
   
   
		// 返回一个 http.HandlerFunc 类型的处理程序,用于处理传入的 HTTP 请求。
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   
   
			// 调用 parser 的 ParseToken 方法,从请求 r 中解析 JWT,同时传入当前密钥 secret 和之前的密钥 authOpts.PrevSecret。
			// tok 是解析出的 JWT 对象,err 是可能出现的错误。
			tok, err := parser.ParseToken(r, secret, authOpts.PrevSecret)
			if err != nil {
   
   
				// 如果解析过程中出现错误,说明 token 无效或解析失败。
				// 调用 unauthorized 函数返回未授权错误,并终止请求处理。
				unauthorized(w, r, err, authOpts.Callback)
				return
			}

			// 检查解析出的 JWT 是否有效。
			if !tok.Valid {
   
   
				// 如果 JWT 无效,调用 unauthorized 函数返回未授权错误,并终止请求处理。
				unauthorized(w, r, errInvalidToken, authOpts.Callback)
				return
			}

			// 尝试将 JWT 的声明(Claims)转换为 jwt.MapClaims 类型。
			// claims 是转换后的声明对象,ok 表示转换是否成功。
			claims, ok := tok.Claims.(jwt.MapClaims)
			if !ok {
   
   
				// 如果转换失败,说明 JWT 中没有有效的声明。
				// 调用 unauthorized 函数返回未授权错误,并终止请求处理。
				// errNoClaims 是一个预定义的错误对象,表示没有声明。
				unauthorized(w, r, errNoClaims, authOpts.Callback)
				return
			}

			// 获取请求的上下文 ctx。
			ctx := r.Context()
			// 遍历 JWT 的声明,将自定义声明添加到上下文中。
			for k, v := range claims {
   
   
				switch k {
   
   
				// 忽略标准的 JWT 声明,如受众、过期时间、ID 等。
				case jwtAudience, jwtExpire, jwtId, jwtIssueAt, jwtIssuer, jwtNotBefore, jwtSubject:
					// 忽略标准的声明,不做处理
				default:
					// 将自定义声明添加到上下文中,键为 k,值为 v。
					ctx = context.WithValue(ctx, k, v)
				}
			}

			// 将带有更新后的上下文的请求传递给下一个处理程序 next 进行处理。
			next.ServeHTTP(w, r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值