textarea不支持pattern等原生敏感词校验,须用JS实现;应按词长倒序排序并转义正则元字符,结合debounce节流与submit保底校验,且服务端必须独立验证原始文本。

文本域()本身不支持 HTML5 原生敏感词校验,必须用 JavaScript 实现;校验时机选 input 还是 blur,直接影响用户体验和性能。
为什么不能用 pattern 或 required 校验敏感词
pattern 属性只对 有效, 完全忽略它;required 只能判断是否为空,无法识别“暴力”“色情”等语义内容。浏览器原生约束验证 API(如 checkValidity())也不提供关键词匹配能力——这层逻辑必须手写或引入库。
- 尝试给
加 pattern:无效,控制台无报错但校验不触发 - 把敏感词当
minlength处理:完全跑偏,长度限制 ≠ 内容过滤 - 依赖
:invalidCSS 伪类高亮:永远不会被标记为 invalid,样式不生效
实时检测该监听 input 还是 blur 事件
监听 input 能做到打字即查,但高频触发易卡顿;监听 blur(失焦)延迟反馈,用户可能已提交。折中方案是:输入时仅做轻量级预检(如长度、基础违禁字符),提交前再跑完整敏感词扫描。
- 直接绑定
textarea.addEventListener('input', filterSensitive):每敲一个字都执行replace(),含 50 个词的词库在低端机上明显掉帧 - 改用
debounce节流(如延迟 300ms):平衡响应与性能,适合长文本编辑场景 - 关键动作必须保底校验:表单
submit事件里调用一次完整过滤,防止绕过前端 JS
replace() 和正则全局匹配的坑
用 new RegExp(word, 'g') 替换敏感词时,若词库含“色”“色情”“色狼”,会出现“***情”“***狼”这种误伤——因为短词先被替换,破坏了长词上下文。必须按词长度倒序排序,优先匹配更长的词。
- 错误写法:
sensitiveWords.forEach(word => text.replace(new RegExp(word, 'g'), '***')):未排序,导致“色情”被拆成“色”+“情”分别替换 - 正确顺序:
sensitiveWords.sort((a, b) => b.length - a.length),再遍历 - 正则需转义特殊字符:
word.replace(/[.*+?^${}()|[]\]/g, '\$&'),否则“1+1”这类词会引发语法错误 - 大小写问题:加
'gi'标志可匹配“暴 力”“BaoLi”,但注意性能损耗比'g'高约 20%
服务端必须重复校验,且不能只靠客户端传来的“过滤后文本”
前端替换只是给用户看的友好提示,攻击者禁用 JS 或抓包重放,就能把原始含敏文本直接发到后端。服务端收到的必须是原始值,而不是前端传来的 clean_text 字段。
- 后端校验逻辑要独立实现,不能复用前端 JS 代码(Node.js 的
RegExp和 Python 的re.sub行为不一致) - 避免简单
str.replace()后就入库:替换后的“***”仍可能被用于构造 XSS,比如<script>***</script>中的星号不影响标签解析 - 真正安全的做法:检测到敏感词后,拒绝整条请求并返回 400,或记录日志后转人工审核,而非自动清洗
敏感词校验不是“替换完就结束”的功能,它的难点在于词序冲突、跨浏览器正则兼容性、前后端职责切分,以及如何不让防御机制本身成为性能瓶颈。最常被跳过的一步,是忘记对词库中的正则元字符做转义——一个没转义的点号(.),就能让整个过滤逻辑失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











