2017-09-29 45 views
14

W poniższym fragmencie chciałbym sprawdzić pola w pierwszej asynchronicznej metodzie.Obsługa błędów za pomocą Node.js, Async i Formidable

Jeśli nie są one prawidłowe, chciałbym natychmiast zwrócić błąd użytkownikowi.

Jak to zrobić?

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

Możesz powrócić zwrotnego z błędem 'zwrotna zwrot (ERR)' jeśli natychmiast z bloku, w którym jest sprawdzana na boisku, że zwrotna będzie bezpośrednio wykonać swoje 'oddzwonienia uchwytu zakresie funkcji gdzie wysyłanych' kod odpowiedzi ". – Zeeshan

Odpowiedz

1

jestem przy założeniu, że jest to dobre miejsce, aby potwierdzić, ponieważ to jest, gdy pola idą w:

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

Proszę dać mi znać, jeśli to pomaga.

+0

Gdzie te błędy są rzucane? Czy istnieje sposób, aby zwrócić błąd do wywołania API? –

+0

W moim kodzie, sądzę, że zostałby wysłany do ostatniej funkcji w serii asynchronicznej przez parametr błędu. Aby wysłać go do wywołania API (zakładam coś podobnego Express), może mógłbyś zrobić "return res.send ('Wartości są puste') –

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

 
});

dodałem kilka uwag w kodzie, gdzie potrzebne, aby pokazać, gdzie i jak stworzyć błąd i jak to się natychmiast przepuszcza się do użytkownika.

referencyjny: Async Documentation

PS: Fragment kodu nie jest możliwy do uruchomienia, ale ma lepszą reprezentację kodu.

- edycja -

Po wiedząc więcej od komentarza, dodając kolejny fragment. Nierozsądnie mieszasz oddzwanianie i obsługę zdarzeń. Możesz po prostu przekazać wywołanie zwrotne do form.parse, a wywołanie zwrotne zostanie wywołane po zebraniu wszystkich pól. Możesz wykonać walidację, natychmiast zwrócić błąd lub po prostu obsłużyć pola formularza od razu.

form.parse(req, function(err, fields, files) { 
    if (err) return res.sendStatus(400); 
    if (fields.areNotValid()) return res.sendStatus(400); 
    // parse fields 
}); 

Można również zarejestrować dla niego obsługę zdarzeń. Wszystkie zdarzenia w miarę ich przepływu będą obsługiwane jednocześnie, podobnie jak 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

Spowoduje to, że wywołanie zwrotne() jest już nazywane błędem, gdy zwrócimy błąd. Callback w formula.on ('end') zgłasza błąd –

+0

@Robben_Ford_Fan_boy Gotcha! Teraz lepiej rozumiem problem i zaktualizowałem swoją odpowiedź. Sprawdź zmiany i daj mi znać, jeśli to pomoże. –

5

chciałbym wyodrębnić formę kontroli do funkcji:

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

Więc teraz możemy realizować czeki i używać Promise.all je podsumować:

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

Jeśli nie wszystkie parametry zostały pomyślnie przekazane, bez końca. Więc zakończmy umowę, jeśli została zakończona:

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

Dzięki temu możemy stworzyć dobry przepływ danych. np:

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