2014-12-09 9 views
5

W pliku Node.js powinienem użyć błędów do sterowania przepływem lub czy powinienem używać ich bardziej jak wyjątków?Najlepsze praktyki NodeJS: Błędy kontroli przepływu?

Piszę kontroler uwierzytelniania i niektóre testy jednostkowe w Sails.js, a obecnie moja metoda rejestracji sprawdza, czy istnieje użytkownik o tej samej nazwie użytkownika. Jeśli użytkownik już istnieje z nazwą użytkownika, moja metoda Model nazywa swoje argumenty wywołania zwrotnego z nowego obiektu Error tak:

Model:

exists: function (options, cb) { 
    User.findOne({ 
     where: { username: typeof options === 'Object' && options.username ? options.username : options }, 
    }).exec(function (err, user) { 
     if (err) return cb(err); 
     if (user) return cb(new Error("A user with that username already exists.")); 
     cb(null, !!user); 
    }); 
}, 

Kontroler:

User.exists(req.body.user.username, function (err, exists) { 
    if (err) { 
    console.log("error: ", err); 
    return res.status(409).json({ 
     message: err 
    });  
    } 

    User.create(req.user).then(function (data) { 
    res.status(201).json({ 
     user: data 
    }); 
    }); 
}); 

Jest to najlepszy ćwiczyć? Nie jestem pewien, czy konwencje węzłów faworyzują błędy w wyjątkowych przypadkach lub kontroli przepływu. Myślę, że powinienem to przerobić, ale zanim to zrobię, chcę poznać konwencje. Myślę, że widziałem kilka przykładów napisanych w ten sposób w Żagle. Dzięki!

+0

Znacznie prostszym sposobem jest banderą 'username' jako unikalna w schemacie modelu i po prostu użyć error Mongoose zwraca w swoim kontrolerze 'User.create()', aby odpowiedzieć 409. Jest to podejście bardziej optymistyczne, ponieważ jeśli użytkownik nie istnieje i jest to ważne żądanie, nie trafiasz dwukrotnie do DB bez powodu . – srquinn

+0

@jibsales To ma sens - ale co się stanie, jeśli wystąpi inny błąd, który wymagać będzie odpowiedzi 500?W językach takich jak C# istnieją różne rodzaje wyjątków i można sprawdzić ten typ. Wiem, że mogłem zrobić coś takiego w Node, gdyby chciałem, ale czy jest to powszechna praktyka? Decyzja, którą podejmuję teraz, wpłynie na sposób, w jaki buduję resztę aplikacji. Na podstawie Twojego komentarza wydaje się, że Węzeł używa błędów do kontroli przepływu zamiast wyjątkowych sytuacji. –

+0

Zobacz moją odpowiedź poniżej – srquinn

Odpowiedz

2

Powyższa odpowiedź jest dobra dla Express, ale w kontrolerach Sails nie powinieneś dzwonić pod numer next; najlepszą praktyką jest zawsze zwracać odpowiedź. W większości przykładowych kodów Żagli nie zobaczysz nawet next jako argumentu funkcji kontrolera akcji. Zauważ też, że Sails ma wbudowany jakiś obiekt default response methods wbudowany bezpośrednio w obiekt res, taki jak res.serverError i res.badRequest, a także res.negotiate, który spróbuje skierować błąd do odpowiedniego programu obsługi na podstawie kodu statusu. Więc Przykładem mogą być manipulowane jako:

Model:

exists: function (options, cb) { 
    User.findOne({ 
     where: { username: typeof options === 'Object' && options.username ? options.username : options }, 
    }).exec(function (err, user) { 
     // res.negotiate will default to a 500 server error 
     if (err) return cb(err); 
     // res.negotiate will just output the status code and error object 
     // as JSON for codes between 400 and 500, unless you 
     // provide a custom view as api/responses/badRequest.ejs 
     if (user) return cb({ 
      status: 409, 
      message: "A user with that username already exists." 
     }); 
     cb(null, !!user); 
    }); 
}, 

Kontroler:

User.exists(req.body.user.username, function (err, exists) { 
    // Let Sails handle those errors for you 
    if (err) {return res.negotiate(err);} 

    User.create(req.user).then(function (data) { 
    res.status(201).json({ 
     user: data 
    }); 
    }); 
}); 
+1

Poprawność tej odpowiedzi - podczas gdy druga jest dobra, jest to zależne od Żagli. Dla porównania, skończyłem robić coś podobnego, ale stworzyłem własne typy błędów, rozszerzając błąd i sprawdzam typ za pomocą obietnic Bluebird. –

2

węzła (lub Javascript naprawdę) może rzucać błędy na wyjątki za pomocą słowa kluczowego throw:

if (something_went_wrong) { 
    throw new Error('Doh!'); 
} 

Można również dodać dodatkowe parametry do obiektu domyślnego Error dać bardziej znaczenie semantyczne do błędów w programie . Po tym, nie chciałbyś rzucić błędu w obsłudze trasy, ponieważ spowodowałoby to awarię procesu i twojego serwera.

Podczas korzystania z funkcji obsługi tras w Sails (lub wyrażania naprawdę), na pewno powinieneś sprawdzić typ błędu i odpowiednio zareagować na klienta.

// -- Route handler 
app.get('/something', function (req, res, next) { 

    DB.create({ username: 'user' }, function (err, docs) { 

    if (err) { 

     // This checks to see if we have a unique error from MongoDB 
     // and send the appropriate response to the client 
     if (err.code === 11000 || error.code === 11001) { 
     return res.send(409); // or return res.json(409, {message: "User exists"}); 
     } 

     // Any other error type is assumed to be an internal error so we pass it 
     // down the chain to the error handler middleware 
     return next(err); 

    } 

    // This is a client error, not an internal error so we respond to the client 
    // with the appropriate client error type 
    if (docs.length === 0) return res.send(404); 

    if (user.notAuthorized) return res.send(403); 

    res.send('All Good'); 

    }); 

}); 

zauważyć, że w przypadku, DB odpowiada błędem wewnętrznego, przechodzimy do funkcji next() który jest odbierany przez obsługę błędów pośredniej w łańcuchu. Każde oprogramowanie pośrednie o wartości 4 jest zdefiniowane jako oprogramowanie pośredniczące do obsługi błędów. Żagle prawdopodobnie zawierają pewną domyślną procedurę obsługi błędów, ale prawdopodobnie możesz ją również przesłonić - musisz sprawdzić odpowiednie dokumenty, aby uzyskać te informacje, ponieważ preferuję kontrolę, którą uzyskuję za pomocą samego Expressa.

+0

Rozumiem. Tak więc w tym przypadku mogę używać błędów do kontroli przepływu, ale muszę sprawdzić kod błędu lub typ lub nazwę - co oznacza, że ​​muszę dowiedzieć się, jakie typy błędów może wyrzucać Mongo lub Sails. Myślę, że robię postępy w tej misji pobierania. –

+0

@ jedd.ahyoung Błędy dla kontroli przepływu w tym sensie, że wartości 'err' oznaczają, że wystąpił błąd. To, czy * ty * używasz go do kontroli przepływu, to inny problem. Rozważ również, że promizujące biblioteki powodują, że konwencje Node ustępują na korzyść normalnej obietnicy. –

+0

@DaveNewton Rzeczywiście. Żagle to domyślnie [Bluebird] (https://www.npmjs.org/package/bluebird) i myślałem o tym, aby go użyć, ponieważ naprawdę wolę ten wzór. Jednak Bluebird udostępnia metodę "catch()" dla swoich błędów, co (choć jest niesamowite) oznacza, że ​​muszę sprawdzić nazwy i typy błędów. –