Обработка ошибок с помощью Node.js, Async и Formableable
В следующем фрагменте я хотел бы проверить поля в первом методе async.
Если они недействительны, я хотел бы немедленно отправить сообщение об ошибке пользователю.
Как это сделать?
var form = new formidable.IncomingForm();
async1.series([
function (callback) {
form.parse(req);
form.on('field', function (name, val) {
// Get the fields
});
form.on('fileBegin', function (name, file) {
if (file.name !== "") {
file.path = __dirname + '/upload/' + file.name;
}
});
callback();
},
function (callback) {
form.on('file', function (name, file) {
try {
// Do something with the file using the fields retrieved from first async method
}
catch (err) {
logger.info(err);
}
});
callback();
}
], function (err) {
//the upload failed, there is nothing we can do, send a 500
if (err === "uploadFailed") {
return res.send(500);
}
if (err) {
throw err;
}
return res.status(200);
});
Ответы
Ответ 1
Я извлечу проверку формы в функцию:
var form = new formidable.IncomingForm();
function check(name, cb, err){
return new Promise((res,rej)=>{
form.on('field', function (n, val) {
if( n !== name) return;
if( cb(val) ){
res(val);
}else{
rej(err);
}
});
});
}
form.parse( req );
Итак, теперь мы можем реализовать проверки и использовать Promise.all, чтобы суммировать их:
Promise.all(
check("username", val => val.length > 4,"username isnt valid"),
check("password", val => true,"we need a password")
).then(_=>res.json({status:200}))
.catch(err => res.json({err}));
Если не все все параметры переданы, это будет бесконечно ждать. Итак, прекратите действие, если оно было закончено:
const ended = new Promise((_,rej)=>form.on("end",()=>rej("params required"));
Promise.race(
ended,
Promise.all(
check("username", val => val.length > 4,"username isnt valid"),
check("password", val => true,"we need a password")
)
).then(_=>res.json({status:200}))
.catch(err => res.json({err}));
Таким образом, мы можем создать хороший поток данных. например:.
const login = Promise.all(
//usable as one liners
check("username", val => val.length >= 8,"username invalid"),
//or more extensible
check("password", val =>{
if( val.length < 8 ) return false;
//other checks
console.log(password);
return true;
},"password invalid")
//the field values are resolved by the promises so we can summarize them below
).then(([username,password])=>
//a random (maybe async) call to evaluate the credentials
checkAgainstDB(username,password)
//we can directly fail here, err is "password invalid" or "username invalid"
).catch(err =>res.json({error:"login failed",details:err}));
//another parameter can be extra handled
const data = check("something",val => val.length);
//we need to summarize all the possible paths (login /data in this case) to one that generates the result
Promise.race(
//here we join them together
Promise.all(login,data)
.then((l,d)=>res.json(whatever),
//and we use the ended promise ( from above ) to end the whole thing
ended
//and at last the errors that can occur if the response ended or that have not been canceled early
).catch(e => res.json(e));
Ответ 2
var form = new formidable.IncomingForm();
async1.series([
function (callback) {
form.parse(req);
form.on('field', function (name, val) {
if (!name || !val) {
// the moment callback is called with an error, async will stop execution of any of the steps
// in the series and execute the function provided as the last argument
// idimoatic node, when calling the callback with instance of Error
return callback(new Error('InvalidParams'));
}
/**
* This is from async documentation: https://caolan.github.io/async/docs.html#series
* Run the functions in the tasks collection in series, each one running once the previous function
* has completed. If any functions in the series pass an error to its callback, no more functions are
* run, and callback is immediately called with the value of the error. Otherwise, callback receives
* an array of results when tasks have completed.
*/
});
form.on('fileBegin', function (name, file) {
if (file.name !== "") {
file.path = __dirname + '/upload/' + file.name;
}
});
form.on('end', function () {
// call callback with null to specify there no error
// if there are some results, call it like callback(null, results);
return callback(null);
});
// if you call the callback immediately after registering event handlers for on('field') etc,
// there will be no time for those events to be triggered, by that time, this function will be
// done executing.
//callback();
},
function (callback) {
form.on('file', function (name, file) {
try {
// Do something with the file using the fields retrieved from first async method
}
catch (err) {
logger.info(err);
return callback(err);
}
});
// This should also not be called immediately
//callback();
}
], function (err) {
//the upload failed, there is nothing we can do, send a 500
if (err === "uploadFailed") {
return res.send(500);
}
if (err.message === 'InvalidParams') {
// This will be immediately returned to the user.
return res.sendStatus(400);
}
if (err) {
// I'm not sure if this was just for the example, but if not, you should not be throwing an error
// at run time.
throw err;
}
return res.status(200);
});
Ответ 3
Я предполагаю, что это хорошее место для проверки, так как это когда появляются поля:
form.on('field', function (name, val) {
//if values are null
if (!name || !val) {
//pass the callback an error
return callback("Values are null")
}
// Get the fields
});
Пожалуйста, дайте мне знать, если это поможет.