中间件系统详解
简介
中间件是 HttpServer 的请求/响应处理管道中的拦截器,可以在请求到达控制器之前和响应发送给客户端之后执行自定义逻辑。
请求流程:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Request │ -> │ 前置 │ -> │ 控制器 │ -> │ 后置 │ -> Response
│ 到达 │ │ 中间件 │ │ 处理 │ │ 中间件 │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘中间件类型
| 类型 | 类 | 执行时机 |
|---|---|---|
| 前置中间件 | cHttpServerRouteBefore | 路由匹配前 |
| 后置中间件 | cHttpServerRouterAfter | 控制器处理后 |
前置中间件 (RouteBefore)
基本结构
vb
' cAuthMiddleware.cls
Option Explicit
Public Sub Entry(ctx As cHttpServerContext)
' 中间件逻辑
' 终止后续处理
' ctx.fIsAbort = True
' 跳过其他中间件
' ctx.fIsSkipNextMiddleWare = True
End Sub常用中间件示例
1. 登录验证中间件
vb
' cAuthCheckMiddleware.cls
Option Explicit
Public Sub Entry(ctx As cHttpServerContext)
' 排除登录接口
If ctx.Request.PathInfo = "/login" Then Exit Sub
If ctx.Request.PathInfo = "/register" Then Exit Sub
' 检查 Session
If Not ctx.Session.Exists("user_id") Then
ctx.Response.State401 "请先登录"
ctx.fIsAbort = True ' 终止后续处理
End If
End Sub2. IP 黑名单中间件
vb
' cIPBlacklistMiddleware.cls
Option Explicit
Dim Blacklist As Scripting.Dictionary
Private Sub Class_Initialize()
Set Blacklist = New Scripting.Dictionary
Blacklist("192.168.1.100") = True
Blacklist("10.0.0.50") = True
End Sub
Public Sub Entry(ctx As cHttpServerContext)
Dim clientIP As String
clientIP = ctx.ClientInfo.IP
If Blacklist.Exists(clientIP) Then
ctx.Response.State403 "您的IP已被封禁"
ctx.fIsAbort = True
End If
End Sub3. 请求日志中间件
vb
' cRequestLogMiddleware.cls
Option Explicit
Public Sub Entry(ctx As cHttpServerContext)
Dim log As String
log = Now & " " & _
ctx.ClientInfo.IP & " " & _
ctx.Request.MethodName & " " & _
ctx.Request.PathInfo
' 写入日志文件
Call WriteLog(log)
' 在上下文中记录开始时间(用于计算响应时间)
ctx.fStartTime = Timer
End Sub
Private Sub WriteLog(msg As String)
Dim f As Integer
f = FreeFile
Open "C:\Logs\access.log" For Append As #f
Print #f, msg
Close #f
End Sub4. CORS 预检处理
vb
' cCorsMiddleware.cls
Option Explicit
Public Sub Entry(ctx As cHttpServerContext)
' 处理 OPTIONS 预检请求
If ctx.Request.Method = ReqOptions Then
ctx.Response.Header("Access-Control-Allow-Origin") = "*"
ctx.Response.Header("Access-Control-Allow-Methods") = "GET, POST, PUT, DELETE, OPTIONS"
ctx.Response.Header("Access-Control-Allow-Headers") = "Content-Type, Authorization"
ctx.Response.Text ""
ctx.fIsAbort = True
End If
End Sub5. 请求频率限制
vb
' cRateLimitMiddleware.cls
Option Explicit
Dim RequestCounts As Scripting.Dictionary
Dim LastReset As Date
Private Sub Class_Initialize()
Set RequestCounts = New Scripting.Dictionary
LastReset = Now
End Sub
Public Sub Entry(ctx As cHttpServerContext)
' 每分钟重置计数
If DateDiff("n", LastReset, Now) >= 1 Then
Set RequestCounts = New Scripting.Dictionary
LastReset = Now
End If
Dim clientIP As String
clientIP = ctx.ClientInfo.IP
' 统计请求次数
If Not RequestCounts.Exists(clientIP) Then
RequestCounts(clientIP) = 0
End If
RequestCounts(clientIP) = RequestCounts(clientIP) + 1
' 限制每分钟 100 次
If RequestCounts(clientIP) > 100 Then
ctx.Response.State429 "请求过于频繁,请稍后再试"
ctx.fIsAbort = True
End If
End Sub中间件注册与优先级
vb
Private Sub Form_Load()
Set Server = New cHttpServer
' 注册中间件(按优先级顺序)
Call Server.RouteBefore.Add("cors", New cCorsMiddleware) ' 第1个执行
Call Server.RouteBefore.Add("ratelimit", New cRateLimitMiddleware) ' 第2个执行
Call Server.RouteBefore.Add("ipblacklist", New cIPBlacklistMiddleware) ' 第3个执行
Call Server.RouteBefore.Add("requestlog", New cRequestLogMiddleware) ' 第4个执行
Call Server.RouteBefore.Add("authcheck", New cAuthCheckMiddleware) ' 第5个执行
' 注册控制器
Call Server.Router.Reg("Api", New cApiController)
Call Server.Router.Add("/api/data", "Api@Data")
Call Server.Start(8080)
End Sub上下文控制标志
| 标志 | 说明 |
|---|---|
ctx.fIsAbort | 设为 True 终止整个请求处理 |
ctx.fIsSkipNextMiddleWare | 设为 True 跳过后续中间件 |
后置中间件 (RouteAfter)
后置中间件用于响应发送后的处理(当前版本为预留接口)。
vb
' cResponseLogMiddleware.cls
Option Explicit
Public Sub Entry(ctx As cHttpServerContext)
' 计算响应时间
If ctx.fStartTime > 0 Then
Dim elapsed As Double
elapsed = Timer - ctx.fStartTime
' 记录慢请求
If elapsed > 1 Then
Call WriteSlowLog(ctx.Request.PathInfo & " 耗时 " & elapsed & " 秒")
End If
End If
End Sub上下文扩展
可以在上下文中添加自定义属性供中间件和控制器共享:
vb
' cHttpServerContext 扩展模块
' 在 MiddleWare 中设置
Public Sub AuthMiddleware(ctx As cHttpServerContext)
If IsValidToken Then
ctx.fUserId = GetUserIdFromToken()
ctx.fUserRole = GetUserRole()
End If
End Sub
' 在控制器中使用
Public Sub GetData(ctx As cHttpServerContext)
' 获取中间件设置的信息
Dim userId As String
userId = ctx.fUserId
' 根据角色返回不同数据
If ctx.fUserRole = "admin" Then
' 返回所有数据
Else
' 返回部分数据
End If
End Sub中间件链执行顺序
请求: GET /api/users
1. cCorsMiddleware -> 通过
2. cRateLimitMiddleware -> 通过
3. cIPBlacklistMiddleware -> 通过
4. cRequestLogMiddleware -> 通过
5. cAuthCheckMiddleware -> 检查 Session
└─> 未登录 -> ctx.fIsAbort = True
请求被终止,返回 401最后更新: 2026-05-17