Scenariusz : rozważ, co następuje, to część kodu z aplikacji sieci Web węzła.
app.get('/users/:id?', function(req, res, next){
var id = req.params.id;
if (id) {
// do something
} else {
next(); //or return next();
}
});
Problem : sprawdzam, który z nich wybrać, po prostu next()
lub return next()
. Powyższy przykładowy kod działa dokładnie tak samo dla obu i nie wykazał żadnej różnicy w wykonaniu.
Pytanie : Czy ktoś może rzucić światło na to, kiedy next()
i kiedy używać return next()
oraz jakąś ważną różnicę?
res.redirect('/')
miałaby miejscereturn res.redirect('/')
w przypadku tego typu sytuacji? Może po prostu lepiej jest zawsze pisać return przed instrukcjami res, aby uniknąć błędów w ustawianiu nagłówków po ich wysłaniu?res.redirect
i najlepiej byłoby z niej korzystać, chyba że masz inne zadania serwera, które chcesz wykonać po przekierowaniu użytkownika.Jak odpowiada @Laurent Perrin:
Podam tutaj przykład, jeśli piszesz oprogramowanie pośredniczące w ten sposób:
app.use((req, res, next) => { console.log('This is a middleware') next() console.log('This is first-half middleware') }) app.use((req, res, next) => { console.log('This is second middleware') next() }) app.use((req, res, next) => { console.log('This is third middleware') next() })
Dowiesz się, że wyjście w konsoli to:
Oznacza to, że po zakończeniu wszystkich funkcji oprogramowania pośredniego uruchamia poniższy kod next ().
Jeśli jednak użyjesz
return next()
, natychmiast wyskoczy wywołanie zwrotne, a poniższy kodreturn next()
w wywołaniu zwrotnym będzie nieosiągalny.źródło
express
ta odpowiedź była dla mnie jaśniejsza niż inne odpowiedzi. Kciuki w górę!res.redirect('/')
wersetachreturn res.redirect('/')
w tego typu sytuacji? Może po prostu lepiej jest zawsze pisaćreturn
przedres
instrukcjami, aby uniknąć błędów w ustawianiu nagłówków po ich wysłaniu?next()
jest częścią oprogramowania pośredniego Connect . Wywołania zwrotne przepływu routera nie dbają o to, czy zwrócisz cokolwiek z funkcji, więcreturn next()
inext(); return;
jest w zasadzie to samo.Jeśli chcesz zatrzymać przepływ funkcji, możesz użyć
next(err)
w następujący sposóbapp.get('/user/:id?', function(req, res, next) { console.log('function one'); if ( !req.params.id ) next('No ID'); // This will return error else next(); // This will continue to function 2 }, function(req, res) { console.log('function two'); } );
Prawie dużo
next()
jest używane do rozszerzania oprogramowania pośredniego Twoich żądań.źródło
next('No ID')
:?next('No ID')
w rzeczywistości wysyła błąd, który przerwie przepływ.Najlepiej w ogóle go nie używać! Wyjaśniam i to też wyjaśniam.
Funkcja next (), która może mieć dowolną nazwę i zgodnie z konwencją, została ustawiona na next. Jest to pośrednio związane z operacjami (PUT, GET, DELETE, ...), które są zwykle wykonywane na tym samym zasobie URI, na przykład
/ user /: id
app.get('/user/:id', function (req,res,next)...) app.put('/user/:id', function (req,res,next)...) app.delete('/user/:id', function (req,res,next)...) app.post('/user/', function ()...)
Teraz, jeśli spojrzysz na app.get, app.put i app.delete używają tego samego uri (/ user /: id), jedyną rzeczą, która je odróżnia, jest ich implementacja. Gdy żądanie jest wysyłane (req) express umieszcza żądanie jako pierwsze w app.get, jeśli jakakolwiek walidacja utworzona, ponieważ to żądanie nie jest dla tego kontrolera nie powiedzie się, przekazuje żądanie do app.put, który jest następną trasą w pliku te, i tak na. Jak widać na poniższym przykładzie.
app.get('/user/:id', function (req,res,next){ if(req.method === 'GET') //whatever you are going to do else return next() //it passes the request to app.put //Where would GET response 404 go, here? or in the next one. // Will the GET answer be handled by a PUT? Something is wrong here. }) app.put('/user/:id', function (req,res,next){ if(req.method === 'PUT') //whatever you are going to do else return next() })
Problem polega na tym, że w końcu przekazujesz żądanie wszystkim kontrolerom z nadzieją, że istnieje taki, który robi to, co chcesz, poprzez walidację żądania. W końcu wszyscy kontrolerzy otrzymują coś, co nie jest dla nich :(.
Jak więc uniknąć problemu next () ?
Odpowiedź jest naprawdę prosta.
1- powinien istnieć tylko jeden identyfikator URI do identyfikacji zasobu
http: // IpServidor / colection /: resource / colection /: resource jeśli twój URI jest dłuższy, powinieneś rozważyć utworzenie nowego URI
Przykład http: // IpServidor / users / pepe / kontakt / contacto1
2-Wszystkie operacje na tym zasobie muszą być wykonywane z poszanowaniem idempotencji czasowników http (get, post, put, delete, ...), więc wywołanie URI ma naprawdę tylko jeden sposób wywołania
POST http://IpServidor/users/ //create a pepe user GET http://IpServidor/users/pepe //user pepe returns PUT http://IpServidor/users/pepe //update the user pepe DELETE http://IpServidor/users/pepe //remove the user pepe
Więcej informacji [ https://docs.microsoft.com/es-es/azure/architecture/best-practices/api-design#organize-the-api-around-resources][1]
Zobaczmy kod! Konkretna implementacja, dzięki której unikamy użycia next ()!
W pliku index.js
//index.js the entry point to the application also caller app.js const express = require('express'); const app = express(); const usersRoute = require('./src/route/usersRoute.js'); app.use('/users', usersRoute );
W pliku usersRoute.js
//usersRoute.js const express = require('express'); const router = express.Router(); const getUsersController = require('../Controllers/getUsersController.js'); const deleteUsersController = require('../Controllers/deleteUsersController.js'); router.use('/:name', function (req, res) //The path is in /users/:name { switch (req.method) { case 'DELETE': deleteUsersController(req, res); break; case 'PUT': // call to putUsersController(req, res); break; case 'GET': getUsersController(req, res); break; default: res.status(400).send('Bad request'); } }); router.post('/',function (req,res) //The path is in /users/ { postUsersController(req, res); }); module.exports = router;
Teraz plik usersRoute.js robi to, czego oczekuje się od pliku o nazwie usersRoute, czyli zarządzania trasami URI / users /
// plik getUsersController.js
//getUsersController.js const findUser= require('../Aplication/findUser.js'); const usersRepository = require('../Infraestructure/usersRepository.js'); const getUsersController = async function (req, res) { try{ const userName = req.params.name; //... res.status(200).send(user.propertys()) }catch(findUserError){ res.status(findUserError.code).send(findUserError.message) } } module.exports = getUsersController;
W ten sposób unikasz użycia next, odprzęgasz kod, zyskujesz na wydajności, rozwijasz SOLID, zostawiasz otwarte drzwi na ewentualną migrację do mikroserwisów i przede wszystkim jest łatwy do odczytania przez programistę.
źródło
Kolejny() :
źródło