创建中间件
在我们的项目中使用的中间件可以大体上分为两类,分别是 前置中间件 和 后置中间件。前置中间件 在请求被服务处理之前执行,而 后置中间件 则在服务处理完请求之后执行。
---
title: 请求处理过程
---
flowchart LR
p1(请求) --> p2(前置中间件) --> p3(服务) --> p4(后置中间件) --> p5(响应)之前注册的 ghttp.MiddlewareHandlerResponse 是一个用于标准化响应的 后置中间件。而我们也将添加一个用于验证之前生成的 JWT 的 前置中间件。
响应处理
找到 ghttp.MiddlewareHandlerResponse 的定义,你会发现它的内容如下:
| |
在第二行有一个 r.Middleware.Next()。一个标准的 后置中间件 形式如下:
func MiddlewareHandlerResponse(r *Request) {
r.Middleware.Next()
// some operations
}这个中间件完成了一些错误处理,并在第39到43行修改了我们的最终响应。这就是之前响应格式奇怪的原因。
为了解决这一问题,我们需要创建另一个 中间件。
创建中间件 logic
GoFrame 提供了一个命令行工具 gf gen service 来生成服务接口。不过在使用之前,我们需要在 logic 目录下创建它的具体实现。在 internal/logic 目录下创建一个 middleware 文件夹,然后创建 middleware.go 文件:
package middleware
import (
"github.com/gogf/gf/v2/net/ghttp"
)
type sMiddleware struct{}
func New() *sMiddleware {
return &sMiddleware{}
}
func (s *sMiddleware) ResponseHandler(r *ghttp.Request) {
// ToDo
}生成 service
现在我们可以使用 gf gen service 命令来生成服务接口了:
$ gf gen service
generating service go file: internal/service\middleware.go
generating init go file: internal/logic\logic.go
gofmt go files in "internal/service"
update main.go
done!可以看到 GoFrame 为我们生成了 internal/service/middleware.go 文件。
logic 目录下的代码后都要手动运行这个命令,你可以使用一些自动运行插件,例如 VSCode 中的 Run on Save。完善中间件逻辑
额外操作
你也可以将 New 函数改为:
func New() service.IMiddleware {
return &sMiddleware{}
}这里仅仅是为了标准化返回类型,并不是强制需求,你也可以不更改。
回到之前在 logic 中创建的文件,首先我们需要注册接口的实现。在你的文件中添加如下代码:
func init() {
service.RegisterMiddleware(New())
}然后我们可以添加一些处理逻辑:
func (s *sMiddleware) ResponseHandler(r *ghttp.Request) {
r.Middleware.Next()
if r.Response.BufferLength() > 0 {
return
}
res := r.GetHandlerResponse()
r.Response.WriteJson(res)
}你也可以模仿原来的中间件来完成自己的响应处理逻辑。但为保简洁,在这里我们直接返回响应。
绑定中间件
要使用中间件,我们还需要将它绑定到对应的路由。更改路由注册文件 internal/cmd/cmd.go 中的中间件:
s.Group("/messages", func(group *ghttp.RouterGroup) {
group.Middleware(service.Middleware().ResponseHandler)
group.Bind(
message.NewV1(),
)
})现在你可以进行和之前相同的测试:
POST http://localhost:8000/messages
{
"user_uid": "0000000000",
"content": "This is my first message."
}curl -X POST -H "Content-Type: application/json" -d '{"user_uid":"0000000000","content":"This is my first message."}' "http://localhost:8000/messages"你会看到响应格式现在是正确的了:
{
"code": 0,
"message": "Success",
"data": null
}JWT 认证
同样,我们也可以在 middleware 中添加 JWT 认证。使用创建的 jwt_auth 服务中提供的函数。
func (s *sMiddleware) Auth(r *ghttp.Request) {
service.JWTAuth().MiddlewareFunc()(r)
r.Middleware.Next()
}由于这是一个 前置中间件,我们需要在函数末尾添加 r.Middleware.Next()。
gf gen service。然后我们可以将中间件绑定到路由:
s.Group("/messages", func(group *ghttp.RouterGroup) {
group.Middleware(
service.Middleware().ResponseHandler,
service.Middleware().Auth,
)
group.Bind(
message.NewV1(),
)
})再尝试一遍之前的请求,我们将得到如下响应:
{
"code": 401,
"message": "query token is empty"
}这是鉴权中间件自动生成的响应,看到它意味着你的请求被中间件拦截了。现在我们需要在请求中添加之前获得的 token。
POST http://localhost:8000/messages
- 使用
Bearer的Authorization并填入<your token> - 在 url 中添加查询参数
?token=<your token>
{
"user_uid": "0000000000",
"content": "This is my first message."
}curl -X POST -H "Content-Type: application/json" -d '{"user_uid":"0000000000","content":"This is my first message."}' "http://localhost:8000/messages?token=<your token>"你将看到成功的响应。