2017-09-29 46 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));