Node.jsでnext()を使用してnext()を返す場合


136

シナリオ:以下は、ノードWebアプリのコードの一部であると考えてください。

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next(); //or return next();
    }
});

問題next()またはでどちらを使用するかを確認していreturn next()ます。上記のサンプルコードはどちらでもまったく同じように機能し、実行に違いはありませんでした。

質問:誰かがこれに光を当てることができますか、いつ、いつnext()使用するreturn next()か、いくつかの重要な違いはありますか?

回答:


141

一部の人々は常にreturn next()、コールバックをトリガーした後に実行が停止するようにすることを書いています。

そうしないと、後でもう一度コールバックをトリガーするリスクがあり、通常は壊滅的な結果になります。コードはそのままでも問題ありませんが、次のように書き直します。

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;

    if(!id)
        return next();

    // do something
});

インデントレベルを節約できます。後でコードをもう一度読むと、next2回呼び出される方法がないと確信しています。


2
同様のことは、真のだろうres.redirect('/')return res.redirect('/')このような状況では?ヘッダーが送信された後にヘッダーを設定するエラーを回避するために、常にresステートメントの前にreturnを書き込む方が良いでしょうか?
Adam D

185

@Laurent Perrinの答えとして:

そうしないと、後でもう一度コールバックをトリガーするリスクがあり、通常は壊滅的な結果になります。

次のようなミドルウェアを作成する場合の例を示します。

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

コンソールの出力は次のとおりです。

This is a middleware
This is second middleware
This is third middleware
This is first-half middleware

つまり、すべてのミドルウェア関数が終了した後、次のコードを実行します。

ただし、を使用return next()すると、コールバックがすぐにジャンプし、コールバックreturn next()内の以下のコードに到達できなくなります。


29
expressこの回答の初心者として、他の回答よりも物事が明確になりました。いいぞ!
マンダリン

1
同様のことは、真のだろうres.redirect('/')return res.redirect('/')このような状況では?ヘッダーが送信された後にヘッダーを設定するエラーを回避するためにreturn、常にresステートメントの前に書く方が良いでしょうか?
Adam D

1
next()の後にコードを記述する必要があるのはなぜですか?ミドルウェアで仕事を終えた後、何もしないのは明らかではありませんか?@PJCHENder
Imran Pollob

1
@ImranPollobは間違いを起こすことがあります。ifs / elses / etcなど、多くのコードを記述する場合。`` `return next()`を忘れるかもしれません
Jone Polvora

46

next()接続ミドルウェアの一部です。ルータの流れのためのコールバックは、あなたの関数から何かを返すのであれば、気にしないreturn next()next(); return;基本的に同じです。

機能の流れを止めたい場合next(err)は以下のように使えます

app.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'); 
    }
);

ほとんどnext()は、リクエストのミドルウェアを拡張するために使用されます。


1
次のようなパラメータを送信できますnext('No ID')か?
Amol M Kulkarni 2013年

7
next('No ID')実際にエラーを送信しているため、フローが壊れます。
drinchev 2013年

next(null、 "somevalue");を使用します。async.waterfallのようなツールの場合、次の関数に値を渡します。データ駆動型の一連の複雑な対話では、通常、関数間でコンテキストオブジェクトを渡します。このようにして、複数のエンドポイントで共有できる汎用関数を作成し、コンテキスト内のデータを介してフローを制御できます
Chad Wilson

5
「next()とnext(); return;を返すので、基本的に同じです。」-私が読む必要があったものだけ。thx @drinchev
Nick Pineda

1
私は反対を観察します(エラーを発生させるとき):next(error)は次のミドルウェアをトリガーしますが、コードを実行し続けます。return next(error)は、実行を次のミドルウェアに委託するだけです。next(e)とreturn next(e)は同じではありません。
Nickolodeon

0

全然使わない方がいい!私は説明します、そしてそれは私がそれを説明することでもあります。

任意の名前を付けることができ、慣例によりnext()関数がnextに設定されています。たとえば、同じURIリソースで一般的に実行される操作(PUT、GET、DELETEなど)に間接的に関連しています。/ 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 ()...)

app.get、app.put、app.deleteで同じuri(/ user /:id)を使用している場合、それらを区別する唯一のものはその実装です。要求が行われると(req)expressは最初にreqをapp.getに配置し、その要求がそのコントローラーに対するものではないために作成した検証が失敗した場合、reqをファイルの次のルートであるapp.putに渡します。オン。以下の例に見られるように。

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

   })

問題は、最終的には、reqの検証を通じて、必要なことを実行するコントローラーがあることを期待して、最終的にすべてのコントローラーにreqを渡すことです。結局のところ、すべてのコントローラーは、それらのためではない何かを受け取ることになります:(。

では、次の()の問題を回避するにはどうすればよいですか?

答えは本当に簡単です。

1- リソースを特定するためのURI1つだけです

http:// IpServidor / colection /:resource / colection /:resource URIがそれより長い場合は、新しいURIの作成を検討する必要があります

http:// IpServidor / users / pepe / contacts / contacto1

2-このリソースに対するすべての操作は、http(get、post、put、deleteなど)のべき等性を尊重して実行する必要があるため、URIへの呼び出しには、実際には1つの呼び出し方法しかありません。

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

詳細[ https://docs.microsoft.com/es-es/azure/architecture/best-practices/api-design#organize-the-api-around-resources][1]

コードを見てみましょう!next()の使用を回避する具体的な実装!

ファイル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 );

ファイル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;

これで、usersRoute.jsファイルは、usersRouteと呼ばれるファイルが実行することを期待されていることを実行します。これは、URI / users /のルートを管理することです。

//ファイル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;

このようにして、次の使用を回避し、コードを分離し、パフォーマンスを向上させ、SOLIDを開発し、マイクロサービスへの移行の可能性に扉を開いたままにします。何よりも、プログラマーが簡単に読み取ることができます。


2
これは不正解です。提案したように、app.getはapp.putに渡されません。一致するリクエストのみが呼び出されるため、メソッドがGETの場合、app.getミドルウェアのみが呼び出されます。ミドルウェアはリクエストメソッドをチェックする必要はありません。あなたの提案は、エクスプレスの主要な機能を無視し、代わりに独自のルーティングを実装します。さらに、あなたの提案は、ルーティングがどこにも渡されないため、使用する唯一のミドルウェアであることを前提としています。
Ravenex

情報が正しくありません。上記の回答をご覧ください。
DDiamond

-3

次() :

この関数を呼び出すと、アプリ内の次のミドルウェア関数が呼び出されます。next()関数はNode.jsまたはExpress APIの一部ではありませんが、ミドルウェア関数に渡される3番目の引数です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.