HTML表单前端校验仅为体验优化,非安全机制;所有校验必须后端重做,checkValidity()和reportValidity()仅检查原生约束,业务逻辑需额外实现。

HTML 表单提交前的数据完整性自检,本质是前端体验优化,不是安全机制;它能拦住误操作,但拦不住恶意修改——所有校验必须在后端重做一遍。
checkValidity() 和 reportValidity() 只检查 HTML 层面规则
这两个方法只响应 required、pattern、min/max、type="email" 等原生约束,不涉及业务逻辑。常见误解包括:
-
checkValidity()返回true,不代表“用户名可用”或“邮箱未注册”,只代表“当前值没违反required或pattern” - 用户用 DevTools 执行
input.value = "admin'; DROP TABLE users;--",再调reportValidity()仍可能返回true(尤其当没设pattern或正则没锚定) - 禁用 JS、删掉
required属性、用curl直接 POST,整个前端校验链就失效
pattern 正则必须显式锚定,否则形同虚设
pattern 默认做子串匹配,不是全字符串匹配。比如 pattern="[0-9]{6}" 会把 abc123456def 当作合法——因为中间含 6 位数字。
- 正确写法必须加
^和$:pattern="^[0-9]{6}$" - 但注意:Chrome 对带
^/$的pattern会报错(如pattern="^1[3-9]\d{9}$"),需改用 JavaScript 校验补位 - 中文字符要显式写出范围:
pattern="^[\u4e00-\u9fa5a-zA-Z0-9_]{2,10}$",\w不匹配汉字 -
type="number"完全忽略pattern属性;粘贴abc后显示为空,但checkValidity()仍返回true
setCustomValidity() 必须成对使用,否则表单永久卡死
这是最常踩的坑:设了错误提示却不清理,后续任何合法输入都提交不了。
立即学习“前端免费学习笔记(深入)”;
- 错误写法:
input.setCustomValidity("密码需含数字");后没重置 - 正确节奏是「验证失败 → 设错;验证通过 → 清空」,例如在
blur或input中:
if (!/^(?=.*\d)/.test(this.value)) {
this.setCustomValidity("密码需含数字");
} else {
this.setCustomValidity("");
}
setCustomValidity("") 是唯一清空方式;delete input.validationMessage 无效novalidate 属性,reportValidity() 不触发浏览器默认提示,得自己渲染错误信息真想接近“完整性”,至少补这三件事
原生 API 只是起点。要显著降低脏数据入库概率,得叠加轻量级服务端协作:
- 提交前用
fetch调轻量接口校验唯一性(如用户名是否存在),并用AbortController防连点 - 所有敏感字段(密码、邮箱、手机号)在
submit事件中手动.trim()再校验,避免首尾空格干扰 - 给
<form>加novalidate,自己用checkValidity()+ 自定义 DOM 提示统一控制,避免浏览器原生弹窗打断流程
真正防篡改、防损坏,靠的是后端校验 + HTTPS + CSRF Token + 输入过滤。前端自检只是让用户少点一次“提交→报错→改→再提交”的循环,别把它当防线。



















