必须前后端双重校验:前端用type="text"搭配inputmode="numeric"和JS实时校验(checkValidity+自定义逻辑),后端需严格类型断言、正则全匹配及范围检查,严禁信任parseInt等静默转换。

用 type="number" 限制只能输数字,但别只靠它防非法输入
浏览器原生的 type="number" 能阻止用户输入字母或符号,看起来很省事。但它不拦得住粘贴、开发者工具修改、或直接设 value 为负数/超大数(比如 -999 或 2000)。更关键的是,Safari 对 min/max 的表单验证支持不一致,光靠属性会漏检。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 必须同时设置
min="0"和max="150"(按业务调整),让浏览器显示合理范围提示 - 加
step="1"防止小数(如25.5)被当作合法年龄 - 仍需在 JS 中二次校验——因为用户可能绕过前端限制
JS 中用 checkValidity() + 自定义逻辑判断是否真合法
checkValidity() 只检查原生约束(required、min/max 等),对“是否为整数”“是否在业务语义范围内”无能为力。比如用户输入 0 或 150,虽满足 min="0" max="150",但未必是有效年龄。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 监听
input和blur事件,实时反馈 - 先调用
inputElement.checkValidity(),再手动判断:Number(inputElement.value) % 1 !== 0(排除小数)、value === ""(空值)、value 120(按业务收紧范围) - 出错时用
setCustomValidity("年龄必须是1–120之间的整数"),再触发reportValidity()
后端必须重验,且不能信任 parseInt() 直接转
前端所有校验都可被跳过,后端拿到的可能是字符串 "18abc"、" 25 "、甚至 null。直接用 parseInt(req.body.age) 会把 "18abc" 变成 18,造成静默错误。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 先做类型断言:确保是字符串,且非空、非空白
- 用正则
/^\d+$/全匹配纯数字字符串,再转成数字 - 再检查范围:
age >= 1 && age - 任何一步失败,统一返回 400 和明确错误字段(如
{"error": "age", "message": "年龄必须是1–120之间的整数"})
移动端 inputmode="numeric" 比 type="number" 更可控
在 iOS 和部分安卓浏览器中,type="number" 会唤起带小数点和符号的键盘,反而增加误输概率;而 inputmode="numeric"(配合 type="text")只唤出纯数字键盘,体验更好,且不影响 JS 控制逻辑。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 写成:
<input type="text" inputmode="numeric" pattern="[0-9]*" ...> -
pattern="[0-9]*"是给旧浏览器的兜底,不影响现代行为 - 保留 JS 校验不变——因为
inputmode不提供任何验证能力,只是键盘提示
.value 可能是 "",而后端收到的可能是 " " 或 undefined。不统一 trim + 类型归一,验证逻辑就会在某个环节悄悄失效。



















