使用 Node.js、Async 和 Formidable 处理错误
Posted
技术标签:
【中文标题】使用 Node.js、Async 和 Formidable 处理错误【英文标题】:Error handling with Node.js, Async and Formidable 【发布时间】:2018-03-11 12:12:29 【问题描述】:在下面的 sn-p 中,我想验证第一个异步方法中的字段。
如果它们无效,我想立即向用户返回一个错误。
我该怎么做?
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);
);
【问题讨论】:
您可以立即从您正在检查字段的 if 块返回带有错误return callback(err)
的回调,该回调将直接执行您发送 response code
的 callback handler function
。
【参考方案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's 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);
);
我在代码中添加了一些 cmets,我需要显示在何处以及如何创建错误以及如何立即将其冒泡给用户。
参考:Async Documentation
附:代码片段不可运行,但它具有更好的代码表示。
-- 编辑--
从评论中了解更多后,添加另一个sn-p。您不合理地混合了回调和事件处理。您可以只将回调传递给 form.parse 并在收集所有字段时调用回调。您可以进行验证、立即返回错误或直接处理表单字段。
form.parse(req, function(err, fields, files)
if (err) return res.sendStatus(400);
if (fields.areNotValid()) return res.sendStatus(400);
// parse fields
);
或者,您可以为其注册事件处理程序。流入的所有事件都将同时处理,例如 async.series。
var form = new formidable.IncomingForm();
form.parse(req);
form.on('field', (name, val) =>
if (!name || val)
console.log('InvalidParams')
return res.sendStatus(400);
);
form.on('fileBegin', (name, file) =>
if (file.name !== "")
file.path = __dirname + '/upload/' + file.name;
);
form.on('file', (name, file) =>
);
form.on('error', (err) =>
console.log('ParsingError');
return res.sendStatus(400);
)
form.on('end', () =>
if (res.headersSent)
console.log('Response sent already')
else
// handle what you want to handle at the end of the form when all task in series are finished
return res.sendStatus(200);
);
【讨论】:
这会在我们返回错误时导致 callback() is already called 错误。 form.on('end') 中的回调抛出错误 @Robben_Ford_Fan_boy 明白了!我现在更好地理解了这个问题并更新了我的答案。请检查修改,如果有帮助,请告诉我。【参考方案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
);
如果这有帮助,请告诉我。
【讨论】:
错误被抛出到哪里?有没有办法将错误返回给 API 调用? 在我的代码中,我相信它会通过错误参数发送到异步系列中的最后一个函数。要将其发送到 API 调用(我假设类似 Express),也许您可以执行 'return res.send('Values are null')以上是关于使用 Node.js、Async 和 Formidable 处理错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 Node.js、Async 和 Formidable 处理错误
使用 Node.js、Async 和 Formidable 处理错误
使用 Javascript(以及 Node.js)使用 async/await 和 Promises 的正确方法是啥 [重复]