Error: Can't set headers after they are sent in middleware for joi validation
Error: Can't set headers after they are sent in middleware for joi validation
我已经创建了一个用于 joi 验证错误处理的中间件,但它 returns 带有一些警告,例如 '错误:发送后无法设置 headers'
错误:
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (D:\nodejs\bigfish\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (D:\nodejs\bigfish\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (D:\nodejs\bigfish\node_modules\express\lib\response.js:267:15)
at Object.JSONResponse [as JR] (D:\nodejs\bigfish\helpers\JsonResponse.js:3:29)
at module.exports (D:\nodejs\bigfish\middlewares\error.js:8:14)
at newFn (D:\nodejs\bigfish\node_modules\express-async-errors\index.js:12:20)
at Layer.handle_error (D:\nodejs\bigfish\node_modules\express\lib\router\layer.js:71:5)
at trim_prefix (D:\nodejs\bigfish\node_modules\express\lib\router\index.js:315:13)
..
const express = require('express');
const Joi = require('joi');
const router = express.Router();
const HelperJoi = require('../helpers/joivalidation');
router.get('/GetRetailerDetails',VerifyToken, async (req,res) => {
//Start Validation Code
const schema = {
RetailerId: Joi.number().required(),
};
HelperJoi.validate(req,res,schema);
//End of Validation code
});
joivalidation.js helpers 文件夹下
const Joi = require('joi');
//This is Helper Function Module for Joi Validation
function JoiValidation(req,res,schema){
const result = Joi.validate(req.query,schema, { abortEarly: false });
if(result.error){
//422 Validation Error
var objError = [];
Object.keys(result.error.details).forEach(function(key) {
objError.push(result.error.details[key]['message']);
});
return res.status(422).json({
'statuscode': 422,
'message': 'Validation Error',
'responsedata': objError
});
}
}
module.exports.validate = JoiValidation
仅仅因为验证器函数 return 是错误情况下的响应并不意味着代码的其余部分不是 运行。
所以需要回传给中间件验证失败,中间件不要继续
例如:
// middleware
if (! HelperJoi.validate(req,res,schema)) {
// Validation failed, so we're done
return;
}
// validator function
if (result.error) {
...
res.status(422).json({
'statuscode': 422,
'message': 'Validation Error',
'responsedata': objError
});
return false;
}
return true;
另一种解决方案是验证器函数将 return "null" 如果验证是肯定的,并且在验证失败的情况下是错误数组,中间件将 return 422 响应本身。这将解耦验证器功能。
HelperJoi.validate 是其中的一个函数,您发送响应然后 return 到作为路由处理程序的调用函数并表示尝试终止请求并设置为 headers 已经发送。使用验证作为中间件或 return 来自 HelperJoi.validate 的验证错误并从路由处理程序响应。
看起来你的实现是错误的。
示例:如何实施JOI
验证
const express = require('express');
const router = express.Router();
const joiHelper = require('../helpers/joiHelper');
router.get('/GetRetailerDetails',VerifyToken, async (req,res) => {
let validationResult = joiHelper.JoiValidation(req.query, joiHelper.getRetailSchema(), {allowUnknown: false});
if (validationResult.error) {
return res.status(422).json({
'statuscode': 422,
'message': 'Validation Error',
'responsedata': joiHelper.parseError(validationResult.error.details)
});
}
//Proceeds your get request
});
joiHelper.js
const Joi = require('joi');
const joiHelper = {};
joiHelper.JoiValidation(object, schema, options = {}){
return Joi.validate(object, schema, options);
};
joiHelper.parseError(errorObject) {
let errorDetail = [];
for (var key in errorObject) {
errorDetail.push(errorObject[key].message);
}
return errorDetail.join(', ').replace(new RegExp('"','g'),'');
}
joiHelper.getRetailSchema () {
const schemaObj = {
RetailerId: Joi.number().required()
};
return Joi.object().keys(schemaObj);
};
module.exports = joiHelper;
我已经创建了一个用于 joi 验证错误处理的中间件,但它 returns 带有一些警告,例如 '错误:发送后无法设置 headers'
错误:
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (D:\nodejs\bigfish\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (D:\nodejs\bigfish\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (D:\nodejs\bigfish\node_modules\express\lib\response.js:267:15)
at Object.JSONResponse [as JR] (D:\nodejs\bigfish\helpers\JsonResponse.js:3:29)
at module.exports (D:\nodejs\bigfish\middlewares\error.js:8:14)
at newFn (D:\nodejs\bigfish\node_modules\express-async-errors\index.js:12:20)
at Layer.handle_error (D:\nodejs\bigfish\node_modules\express\lib\router\layer.js:71:5)
at trim_prefix (D:\nodejs\bigfish\node_modules\express\lib\router\index.js:315:13)
..
const express = require('express');
const Joi = require('joi');
const router = express.Router();
const HelperJoi = require('../helpers/joivalidation');
router.get('/GetRetailerDetails',VerifyToken, async (req,res) => {
//Start Validation Code
const schema = {
RetailerId: Joi.number().required(),
};
HelperJoi.validate(req,res,schema);
//End of Validation code
});
joivalidation.js helpers 文件夹下
const Joi = require('joi');
//This is Helper Function Module for Joi Validation
function JoiValidation(req,res,schema){
const result = Joi.validate(req.query,schema, { abortEarly: false });
if(result.error){
//422 Validation Error
var objError = [];
Object.keys(result.error.details).forEach(function(key) {
objError.push(result.error.details[key]['message']);
});
return res.status(422).json({
'statuscode': 422,
'message': 'Validation Error',
'responsedata': objError
});
}
}
module.exports.validate = JoiValidation
仅仅因为验证器函数 return 是错误情况下的响应并不意味着代码的其余部分不是 运行。
所以需要回传给中间件验证失败,中间件不要继续
例如:
// middleware
if (! HelperJoi.validate(req,res,schema)) {
// Validation failed, so we're done
return;
}
// validator function
if (result.error) {
...
res.status(422).json({
'statuscode': 422,
'message': 'Validation Error',
'responsedata': objError
});
return false;
}
return true;
另一种解决方案是验证器函数将 return "null" 如果验证是肯定的,并且在验证失败的情况下是错误数组,中间件将 return 422 响应本身。这将解耦验证器功能。
HelperJoi.validate 是其中的一个函数,您发送响应然后 return 到作为路由处理程序的调用函数并表示尝试终止请求并设置为 headers 已经发送。使用验证作为中间件或 return 来自 HelperJoi.validate 的验证错误并从路由处理程序响应。
看起来你的实现是错误的。
示例:如何实施JOI
验证
const express = require('express');
const router = express.Router();
const joiHelper = require('../helpers/joiHelper');
router.get('/GetRetailerDetails',VerifyToken, async (req,res) => {
let validationResult = joiHelper.JoiValidation(req.query, joiHelper.getRetailSchema(), {allowUnknown: false});
if (validationResult.error) {
return res.status(422).json({
'statuscode': 422,
'message': 'Validation Error',
'responsedata': joiHelper.parseError(validationResult.error.details)
});
}
//Proceeds your get request
});
joiHelper.js
const Joi = require('joi');
const joiHelper = {};
joiHelper.JoiValidation(object, schema, options = {}){
return Joi.validate(object, schema, options);
};
joiHelper.parseError(errorObject) {
let errorDetail = [];
for (var key in errorObject) {
errorDetail.push(errorObject[key].message);
}
return errorDetail.join(', ').replace(new RegExp('"','g'),'');
}
joiHelper.getRetailSchema () {
const schemaObj = {
RetailerId: Joi.number().required()
};
return Joi.object().keys(schemaObj);
};
module.exports = joiHelper;