敏感词过滤必须在Interceptor层实现,需手动解析请求体、用Aho-Corasick构建DFA词库匹配,并将清洗结果存入c.Params或c.RenderArgs供Controller使用。

Revel框架里敏感词过滤该挂在哪一层
必须在 Interceptor 里做,不能塞进 Controller 或模板里。Revel 的请求生命周期里,Interceptor 是唯一能统一拦截所有 HTTP 请求、且早于 Controller 执行的扩展点。你如果把过滤逻辑写在某个 App.Index() 里,那漏掉一个 Action 就等于放行一次违规内容;写在模板里更危险——前端可绕过,服务端根本没看见原始输入。
怎么让 Interceptor 拿到原始表单/JSON 数据
Revel 默认不自动解析 application/json 请求体到 params,而 params.Get 只对 URL 查询参数和 application/x-www-form-urlencoded 有效。所以得手动读取:
- 对
POST/PUT请求,先调用req.ParseForm()(兼容表单)或io.ReadAll(req.Body)(兼容 JSON),再用json.Unmarshal解析结构体 - 别直接对
req.Body多次读取——它是一次性流,第二次读就是空字节 - 如果用了
revel.Intercept,记得在 Interceptor 函数末尾调用return nil继续链路,否则请求就卡死了
敏感词匹配用正则还是 DFA
词库少于 50 个时,strings.Contains + 遍历够用;超过 100 个就必须上 DFA(比如 aho-corasick Go 库)。Revel 是 Go 写的,别学 Java 那套“每个词建一个 regexp.MustCompile”,正则编译开销大,且 | 拼接万级词会触发 regexp 包的 panic(regexp: Compile: error parsing regexp)。
实操建议:
- 启动时从
conf/app.conf读取词库路径,用ioutil.ReadFile加载并构建ahocorasick.Trie实例,存进revel.AppConfig或全局变量 - 匹配时用
trie.FindAllLongest,避免“北京”命中了“京”这种短词误伤 - 替换统一用
*而非***,长度和原词一致,防止前端靠星号数量反推原词
过滤后怎么把清洗结果传给 Controller
Revel 没有类似 Servlet 的 HttpServletRequestWrapper,没法代理 Request 对象。正确做法是把清洗后的字段值存在 c.Params 或 c.RenderArgs 里:
- 例如清洗完
content字段,执行c.Params.Add("clean_content", cleaned) - Controller 中用
c.Params.Get("clean_content")取值,而不是再读原始req.FormValue("content") - 如果涉及多个字段,建议封装成 struct,用
c.RenderArgs["filtered"] = myStruct传递
注意:别改 c.Params.Values 里的原始值,否则后续 Interceptor(比如日志记录)看到的还是脏数据。


















