express-validator returns 两次验证错误
express-validator returns validation errors twice
我想使用 Express-Validator 验证请求 object。假设我有两条路线,一条 GET /users/:id (fetchUserById) 和 POST /users (createUser) 路线
this.router = express.Router();
this.router.route('/').post(this.userRequestValidator.createUser, this.userController.createUser);
this.router.route('/:id').get(this.userRequestValidator.fetchUserById, this.userController.fetchUserById);
如您所见,我在调用控制器逻辑之前调用了验证中间件。首先,我创建了一个基本验证器来处理验证错误并在失败时返回 HTTP 400。
export abstract class RequestValidator {
protected validate = async (request: Request, response: Response, next: NextFunction): Promise<void> => {
const errors: Result<ValidationError> = validationResult(request);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
} else {
next();
}
};
}
我的验证器函数 userRequestValidator.createUser 和 userRequestValidator.fetchUserById 只需扩展 RequestValidator 并实现验证
export class UserRequestValidator extends RequestValidator {
public createUser = [
body('username')
.isString()
.exists(),
body('password')
.isString()
.exists(),
this.validate,
];
public fetchUserById = [
param('id')
.isString()
.isUUID()
.exists(),
this.validate,
];
}
当我打电话给 GET localhost:3000/users/abc
时,我得到了这个回复
{
"errors": [
{
"value": "abc",
"msg": "Invalid value",
"param": "id",
"location": "params"
}
]
}
这是我期待的回应。但是当我用一个空 body 调用 POST localhost:3000/users
时,我得到了这个响应
{
"errors": [
{
"msg": "Invalid value",
"param": "username",
"location": "body"
},
{
"msg": "Invalid value",
"param": "username",
"location": "body"
},
{
"msg": "Invalid value",
"param": "password",
"location": "body"
},
{
"msg": "Invalid value",
"param": "password",
"location": "body"
}
]
}
有人知道我该如何解决这个问题或者我的设置有什么问题吗?
我不知道为什么当 req.body
是一个空对象时 - {}
,验证器将 运行 通过验证链的所有节点。您可以再次检查,为每个条件添加每个消息,如下所示:
class UserRequestValidator extends RequestValidator {
public createUser = [
body('username')
.isString().withMessage('username must be a string') // you can see both error messages in the response
.exists().withMessage('username must be exist'),
body('password') // the same for this field
.isString()
.exists(),
this.validate,
];
public fetchUserById = [
param('id') // because id is exist in `req.params`, then only one test has been executed.
.isString().withMessage('id must be a string')
.isUUID()
.exists(),
this.validate,
];
}
我在 https://github.com/express-validator/express-validator/issues/638 中找到了适合您的情况的解决方案,在第一个错误中使用 .bail()
函数停止链。
然后你的验证器 class 会像:
class UserRequestValidator extends RequestValidator {
public createUser = [
body('username')
// always check exists() first
.exists().withMessage('username must be exist').bail()
.isString().withMessage('username must be a string').bail(),
body('password')
.exists().bail()
.isString().bail(),
this.validate,
];
public fetchUserById = [
param('id')
.isString()
.isUUID()
.exists(),
this.validate,
];
}
您也可以在检索错误数组时将onlyFirstError
设置为true
。
来自 documentation:
If the option onlyFirstError is set to true, then only the first error
for each field will be included
用法示例:
function validateRequestParams (req, res, next) {
const errors = validationResult(req)
if (errors.isEmpty()) {
return next()
} else {
return res.status(400).json({
bodyValidationErrors: errors.array({ onlyFirstError: true })
})
}
}
我想使用 Express-Validator 验证请求 object。假设我有两条路线,一条 GET /users/:id (fetchUserById) 和 POST /users (createUser) 路线
this.router = express.Router();
this.router.route('/').post(this.userRequestValidator.createUser, this.userController.createUser);
this.router.route('/:id').get(this.userRequestValidator.fetchUserById, this.userController.fetchUserById);
如您所见,我在调用控制器逻辑之前调用了验证中间件。首先,我创建了一个基本验证器来处理验证错误并在失败时返回 HTTP 400。
export abstract class RequestValidator {
protected validate = async (request: Request, response: Response, next: NextFunction): Promise<void> => {
const errors: Result<ValidationError> = validationResult(request);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
} else {
next();
}
};
}
我的验证器函数 userRequestValidator.createUser 和 userRequestValidator.fetchUserById 只需扩展 RequestValidator 并实现验证
export class UserRequestValidator extends RequestValidator {
public createUser = [
body('username')
.isString()
.exists(),
body('password')
.isString()
.exists(),
this.validate,
];
public fetchUserById = [
param('id')
.isString()
.isUUID()
.exists(),
this.validate,
];
}
当我打电话给 GET localhost:3000/users/abc
时,我得到了这个回复
{
"errors": [
{
"value": "abc",
"msg": "Invalid value",
"param": "id",
"location": "params"
}
]
}
这是我期待的回应。但是当我用一个空 body 调用 POST localhost:3000/users
时,我得到了这个响应
{
"errors": [
{
"msg": "Invalid value",
"param": "username",
"location": "body"
},
{
"msg": "Invalid value",
"param": "username",
"location": "body"
},
{
"msg": "Invalid value",
"param": "password",
"location": "body"
},
{
"msg": "Invalid value",
"param": "password",
"location": "body"
}
]
}
有人知道我该如何解决这个问题或者我的设置有什么问题吗?
我不知道为什么当 req.body
是一个空对象时 - {}
,验证器将 运行 通过验证链的所有节点。您可以再次检查,为每个条件添加每个消息,如下所示:
class UserRequestValidator extends RequestValidator {
public createUser = [
body('username')
.isString().withMessage('username must be a string') // you can see both error messages in the response
.exists().withMessage('username must be exist'),
body('password') // the same for this field
.isString()
.exists(),
this.validate,
];
public fetchUserById = [
param('id') // because id is exist in `req.params`, then only one test has been executed.
.isString().withMessage('id must be a string')
.isUUID()
.exists(),
this.validate,
];
}
我在 https://github.com/express-validator/express-validator/issues/638 中找到了适合您的情况的解决方案,在第一个错误中使用 .bail()
函数停止链。
然后你的验证器 class 会像:
class UserRequestValidator extends RequestValidator {
public createUser = [
body('username')
// always check exists() first
.exists().withMessage('username must be exist').bail()
.isString().withMessage('username must be a string').bail(),
body('password')
.exists().bail()
.isString().bail(),
this.validate,
];
public fetchUserById = [
param('id')
.isString()
.isUUID()
.exists(),
this.validate,
];
}
您也可以在检索错误数组时将onlyFirstError
设置为true
。
来自 documentation:
If the option onlyFirstError is set to true, then only the first error for each field will be included
用法示例:
function validateRequestParams (req, res, next) {
const errors = validationResult(req)
if (errors.isEmpty()) {
return next()
} else {
return res.status(400).json({
bodyValidationErrors: errors.array({ onlyFirstError: true })
})
}
}