数据验证(Validate)
为什么要验证
在用户使用表单发送数据到后端、后端将数据写入数据库的过程中,如果用户输入了一些无效的数据,可能会影响整个代码的逻辑。(避免提交数据不合法)
如何进行验证
我们可以在不同的地方对数据进行验证:
在客户端进行验证(可选):在发送任何请求到服务端之前,通过 JS 监听输入事件,然后在用户进行表单输入时检查,在页面上进行反馈显示。这可以提高用户的体验。
在客户端验证是可选的,它并不安全。因为客户端使用的 JS 是在浏览器中运行的,用户可以看到、更改或禁用 JS 代码,不利于保护安全数据发送到服务器。
在服务端进行验证(必须):将任何数据存储在数据库之前进行验证,保证存储数据的正确性。并且有些验证功能需要查询数据库,在服务器端进行验证能做的事要多一些。
用户无法看到、更改或禁用代码,因为这些都发生在服务器上,而不是浏览器中。
数据库内置验证(可选):大多数数据库引擎都有一个内置验证,但是如果在服务端进行了良好的验证,基本上不需要。
在 Node(Express)中进行数据验证
安装验证器
在 Node(Express)中,我们可以安装第三方验证器express-validator来辅助我们进行数据的验证:
npm install --save express-validator
进行验证
引入express-validator/check中的check(),check()接收两个参数,第一个参数为作为检查对象的 name;第二个参数是触发校验错误的信息:
const { check } = require('express-validator/check');
const app = express();
app.use('/signup', check('email').isEmail(), authController.postSignup)'); // 通过isEmail()检查渲染页面中name为email的输入选项是否为有效的Email格式
自定义验证
除了直接使用已有的内置验证器函数,我们也使用custom()自定义验证器。
custom()接收一个回调函数,其中回调函数中第一个参数为需要验证的值;第二个参数为一个对象,我们可以从中提取一些信息(如请求、位置、路径):
app.use(
"/signup",
check("email")
.isEmail()
.withMessage("Please enter a valid email.")
.custom((value, { req }) => {
// 自定义验证逻辑
if (value === "test@test.com") {
throw new Error("This email address if forbidden."); // 抛出错误异常消息
}
return true;
}),
authController.postSignup
);
验证再次确认密码
我们可以用数组,同时注册验证多字段:
app.use( "/signup", [ check("email") .isEmail() .withMessage("Please enter a valid email.") .custom((value, { req }) => { if (value === "test@test.com") { throw new Error("This email address if forbidden."); } return true; }), body( "password", "Please enter a password with only numbers and text and at least 5 characters." ) .isLength({ min: 5 }) .isAlphanumeric(), body("confirmPassword").custom((value, { req }) => { if (value !== req.body.password) { // req.body.password获取输入请求的密码 throw new Error("Password have to match!"); } return true; }), ], authController.postSignup );
指定验证
在引入check()时,我们可以指定引入传入请求时的一些信息(例如 body、param、query、cookie、header 等),用法和check()相同:
const { check, body } = require('express-validator/check')
...
app.use(
'/signup',
[
check('email')
.isEmail()
.withMessage('Please enter a valid email.')
.custom((value, {req}) => {
if (value === 'test@test.com') {
throw new Error('This email address if forbidden.')
}
return true;
}),
body(
'password',
'Please enter a password with only numbers and text and at least 5 characters.'
)
.isLength({min: 5})
.isAlphanumeric()
],
authController.postSignup
);
isLength({min: 5}):最小长度为 5
isAlphanumeric():允许数字和普通字符
验证结果
引入express-validator/check中的validationResult(),validationResult()中包含了所有验证的结果:
const { validationResult } = require("express-validator/check");
exports.postSignup = (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
const confirmPassword = req.body.confirmPassword;
const errors = validationResult(req); // 存储使用验证中间件的请求里的验证结果
if (!errors.isEmpty()) {
// 检测errors中是否有错误信息
console.log(errors.array()); // 打印错误信息数组
return res.status(422).render("auth/signup", {
// 返回422状态码,重新返回注册页面
path: "/signup",
pageTitle: "Signup",
errorMessage: errors.array()[0].msg, // 错误信息数组里的每一项的msg为错误信息
});
}
};
自定义错误信息
可以在注册中间件函数时添加withMessage()来自定义错误信息:
app.use(
"/signup",
check("email").isEmail().withMessage("Please enter a valid email."),
authController.postSignup
);
附录
express-validator 内置验证器函数
isEmail():输入是否为 Email 格式。
isURL():输入是否为一个 url 网址形式。
isFloat():输入保留一位小数。
isLength({}):是否限制输入长度。接收一个对象,对象内设置最长或最短字符数量。
withMessage():定义错误信息。
custom():自定义验证函数。
isAlphanumeric():是否数字和普通字符。
isString():是否是字符串形式。
normalizeEmail():规范化 Email 格式。
trim():删除多余空格。