Iris框架需手动集成DFA算法+中间件实现敏感词过滤,因其纯函数式中间件链(func(ctx iris.Context))与Spring的反射式HandlerInterceptor无等价机制;正确做法是在启动时构建DFA树,通过中间件读取原始body、递归遍历JSON字符串字段并替换为*。

Iris 框架本身不内置敏感词过滤拦截器,必须手动集成 DFA 算法 + 中间件(middleware)实现,且不能依赖 Spring MVC 那套 HandlerInterceptor 机制——Iris 是 Go 语言框架,没有 Servlet 生命周期概念。
为什么不能直接搬 Spring 的拦截器写法
Iris 的请求处理模型是纯函数式中间件链,iris.Handler 类型本质是 func(ctx iris.Context)。Spring 的 preHandle/postHandle 是基于反射和 Bean 生命周期的,Go 里没等价物。硬套 Java 思路会导致:
- 误以为能用
@Component+@Order注册拦截器(Iris 不支持注解扫描) - 试图在控制器方法里加切面逻辑(Go 没运行时织入能力)
- 把敏感词检查塞进模板渲染阶段(晚了,数据可能已落库或发往下游)
正确做法:用 DFA 树构建 KeywordFilter + 请求体中间件
核心是把敏感词库构建成内存中的 trie 树(即 DFA),再在中间件中对 ctx.Request().Body 或解析后的字段做实时匹配。关键点:
- 敏感词加载必须在应用启动时完成(比如
init()或main()开头),避免每次请求重建树 - 中间件应优先读取原始 body(用
ctx.ReadBody()),而不是等ctx.PostValue()—— 后者会触发自动解析,可能丢掉原始编码或被 multipart 解析污染 - 若接口接收 JSON,需先
json.Unmarshal成 map 或 struct,再递归遍历字符串字段;不能只扫顶层 key - 替换策略建议用
***而非删除,否则可能破坏 JSON 结构或导致前端校验失败
示例中间件片段:
func SensitiveWordMiddleware() iris.Handler {
dfa := buildDFAFromWordList([]string{"日本人", "打倒", "暴力"})
return func(ctx iris.Context) {
body, err := ctx.ReadAll()
if err != nil {
ctx.StatusCode(400)
ctx.WriteString("invalid request body")
return
}
// 尝试 JSON 解析
var data map[string]interface{}
if json.Unmarshal(body, &data) == nil {
scrubbed := scrubMap(data, dfa)
newBody, _ := json.Marshal(scrubbed)
ctx.Request().Body = io.NopCloser(bytes.NewReader(newBody))
}
ctx.Next()
}
}
容易踩的坑:body 读取不可重复 & 编码问题
Iris 的 ctx.Request().Body 是单次读取流,中间件里调一次 ReadAll() 后,后续控制器再调 ctx.ReadJSON() 会读到空内容。必须重置:
- 读完后用
io.NopCloser(bytes.NewReader(newBody))替换原Body字段 - 若敏感词含中文,确保词库文件保存为 UTF-8(无 BOM),否则
buildDFAFromWordList可能按字节拆分出错 - 不要用正则做全量匹配(如
regexp.MustCompile(`日本人|打倒`)),DFA 在万级词库下比正则快 10 倍以上,且不会因回溯爆炸崩溃
真正麻烦的是嵌套结构里的动态键名(比如评论里的 content、用户提交的 extra.fields[0].value),这种必须写递归 scrub 函数,且要跳过非字符串类型字段——漏掉这一层,过滤就形同虚设。


















