2017-09-29 42 views
14

在下面的代码片段中,我想验证第一个异步方法中的字段。使用Node.js,Async和Formidable处理错误

如果它们无效,我想立即向用户返回错误。

我该怎么做?

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); 

}); 
+0

您可以返回一个错误回调'返回回调(ERR)'立即从if块,你正在检查的领域,即回调将直接执行你的'回调处理器function'你在哪里发送'响应代码'。 – Zeeshan

回答

1

我猜想,这是验证,因为这是当字段来了一个好去处:

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 
}); 

请让我知道,如果这有助于。

+0

那些错误被抛到哪里?有没有办法将错误返回给API调用? –

+0

在我的代码中,我相信它会通过error参数发送到异步系列中的最后一个函数。要将它发送给API调用(我假设类似Express),也许你可以'返回res。send('Values are null') –

3

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); 
 

 
});

我说在我需要显示在哪里以及如何创建一个错误,它是如何立即冒泡用户代码中的一些注释。

参考:Async Documentation

P.S.代码片段不可运行,但它具有更好的代码表示形式。

- 编辑 -

知道从评论更多,增加另一个片段之后。你无理地混合回调和事件处理。您可以将回调传递给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); 
 
    } 
 
});

+0

当我们返回错误时,这将导致回调()已被调用错误。 form.on中的回调('end')会引发错误 –

+0

@Robben_Ford_Fan_boy难题!我现在更好地理解了这个问题并更新了我的答案。请检查编辑并让我知道是否有帮助。 –

5

我想提取表单检查到的函数:

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})); 

如果不是所有的参数都已通过,这将w无休无止。所以让我们终止,如果它结束:

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));