Apa parameter "selanjutnya" yang digunakan untuk di Express?


295

Misalkan Anda memiliki blok kode sederhana seperti ini:

app.get('/', function(req, res){
    res.send('Hello World');
});

Fungsi ini memiliki dua parameter, reqdan res, yang masing-masing mewakili objek permintaan dan respons.

Di sisi lain, ada fungsi lain dengan parameter ketiga yang disebut next. Sebagai contoh, mari kita lihat kode berikut:

app.get('/users/:id?', function(req, res, next){ // Why do we need next?
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next(); // What is this doing?
    }
});

Saya tidak mengerti apa gunanya next()atau mengapa ini digunakan. Dalam contoh itu, jika id tidak ada, apa yang nextsebenarnya dilakukan?


13
Berikutnya cukup memungkinkan penangan rute berikutnya sejalan untuk menangani permintaan. Dalam hal ini, jika id pengguna ada, kemungkinan akan digunakan res.senduntuk menyelesaikan permintaan. Jika tidak ada, ada kemungkinan handler lain yang akan mengeluarkan kesalahan dan menyelesaikan permintaan itu.
Dominic Barnes

1
jadi Anda mengatakan saya memiliki app.post('/login',function(req,res))setelah app.get('/users',function(req,res)) itu akan memanggil login menjadi rute berikutnya dalam file app.js dengan memanggil next ()?
Menztrual

2
Tidak, Anda harus merujuk ke bagian dokumentasi Express.js ini: expressjs.com/guide.html#passing-route control
Dominic Barnes

3
Pada dasarnya, rute berikutnya yang akan dijalankan adalah rute lain yang cocok dengan URL permintaan. Dalam hal ini, jika rute lain didaftarkan melalui app.get("/users"), maka itu akan dijalankan jika pawang di atas memanggil berikutnya.
Dominic Barnes

3
Berikutnya pada dasarnya hanyalah sebuah panggilan balik.
Jonathan Ong

Jawaban:


266

Ini melewati kontrol ke rute yang cocok berikutnya . Dalam contoh yang Anda berikan, misalnya, Anda mungkin mencari pengguna di database jika iddiberikan, dan menugaskannya req.user.

Di bawah, Anda dapat memiliki rute seperti:

app.get('/users', function(req, res) {
  // check for and maybe do something with req.user
});

Karena / users / 123 akan cocok dengan rute dalam contoh Anda terlebih dahulu, yang pertama akan memeriksa dan menemukan pengguna 123; maka /usersdapat melakukan sesuatu dengan hasil itu.

Route middleware adalah alat yang lebih fleksibel dan kuat, menurut saya, karena itu tidak bergantung pada skema URI tertentu atau pemesanan rute. Saya akan cenderung untuk memodelkan contoh yang ditampilkan seperti ini, dengan asumsi Usersmodel dengan async findOne():

function loadUser(req, res, next) {
  if (req.params.userId) {
    Users.findOne({ id: req.params.userId }, function(err, user) {
      if (err) {
        next(new Error("Couldn't find user: " + err));
        return;
      }

      req.user = user;
      next();
    });
  } else {
    next();
  }
}

// ...

app.get('/user/:userId', loadUser, function(req, res) {
  // do something with req.user
});

app.get('/users/:userId?', loadUser, function(req, res) {
  // if req.user was set, it's because userId was specified (and we found the user).
});

// Pretend there's a "loadItem()" which operates similarly, but with itemId.
app.get('/item/:itemId/addTo/:userId', loadItem, loadUser, function(req, res) {
  req.user.items.append(req.item.name);
});

Mampu mengendalikan aliran seperti ini cukup berguna. Anda mungkin ingin memiliki halaman tertentu hanya tersedia untuk pengguna dengan bendera admin:

/**
 * Only allows the page to be accessed if the user is an admin.
 * Requires use of `loadUser` middleware.
 */
function requireAdmin(req, res, next) {
  if (!req.user || !req.user.admin) {
    next(new Error("Permission denied."));
    return;
  }

  next();
}

app.get('/top/secret', loadUser, requireAdmin, function(req, res) {
  res.send('blahblahblah');
});

Semoga ini memberi Anda beberapa inspirasi!


Bisa dibilang begitu! Saya akan lebih cenderung melakukan hal semacam ini dengan middleware rute , karena tidak menyandingkan logika dengan urutan rute tertentu, atau struktur URI tertentu.
Asherah

5
mengapa kadang-kadang Anda kembali berikutnya () tetapi kadang-kadang tidak
John

6
@ John: nilai pengembalian sebenarnya diabaikan; Saya hanya ingin kembali ke sana untuk memastikan saya tidak menelepon next()lagi. Itu akan sama jika saya hanya menggunakan next(new Error(…)); return;.
Asherah

1
@ level0: nilai kembali diabaikan; Anda bisa menganggapnya singkatan next(new Error(…)); return;. Jika kami meneruskan nilai next, itu dianggap sebagai kesalahan secara sepihak . Saya belum melihat ke kode express terlalu banyak, tetapi gali sekitar dan Anda akan menemukan apa yang Anda butuhkan :)
Asherah

1
@ Level0: (Aku sudah berubah return next(…);untuk next(…); return;jadi kurang membingungkan.)
berhala

87

Saya juga memiliki masalah dalam memahami next (), tetapi ini membantu

var app = require("express")();

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write("Hello");
    next(); //remove this and see what happens 
});

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write(" World !!!");
    httpResponse.end();
});

app.listen(8080);

3
Sangat singkat! Terima kasih! Tetapi bagaimana Anda memastikan bahwa yang pertama .getdipanggil dan bukan yang ke-2?
JohnnyQ

18
@JohnnyQ Ini akan menjadi eksekusi atas ke bawah
Tapash

59

Sebelum memahami next, Anda perlu memiliki sedikit gagasan tentang siklus Request-Response dalam simpul meskipun tidak banyak detail. Itu dimulai dengan Anda membuat permintaan HTTP untuk sumber daya tertentu dan berakhir ketika Anda mengirim respons kembali ke pengguna yaitu ketika Anda menemukan sesuatu seperti res.send ('Hello World');

mari kita lihat contoh yang sangat sederhana.

app.get('/hello', function (req, res, next) {
  res.send('USER')
})

Di sini kita tidak perlu next (), karena resp.send akan mengakhiri siklus dan menyerahkan kontrol kembali ke rute middleware.

Sekarang mari kita lihat contoh lain.

app.get('/hello', function (req, res, next) {
  res.send("Hello World !!!!");
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});

Di sini kita memiliki 2 fungsi middleware untuk jalur yang sama. Tapi Anda akan selalu mendapat respons dari yang pertama. Karena yang dipasang pertama kali di tumpukan middleware dan kirim ulang akan mengakhiri siklus.

Tetapi bagaimana jika kita selalu tidak menginginkan "Hello World !!!!" respon balik. Untuk beberapa kondisi kita mungkin menginginkan "Hello Planet !!!!" tanggapan. Mari kita modifikasi kode di atas dan lihat apa yang terjadi.

app.get('/hello', function (req, res, next) {
  if(some condition){
    next();
    return;
  }
  res.send("Hello World !!!!");  
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});

Apa yang nextdilakukan di sini. Dan ya, Anda mungkin memiliki gusses. Ini akan melewati fungsi middleware pertama jika kondisinya benar dan memanggil fungsi middleware berikutnya dan Anda akan mendapat "Hello Planet !!!!"respons.

Jadi, selanjutnya lewati kontrol ke fungsi selanjutnya di tumpukan middleware.

Bagaimana jika fungsi middleware pertama tidak mengirim kembali respons apa pun tetapi jalankan logika dan kemudian Anda mendapatkan respons kembali dari fungsi middleware kedua.

Sesuatu seperti di bawah ini: -

app.get('/hello', function (req, res, next) {
  // Your piece of logic
  next();
});

app.get('/hello', function (req, res, next) {
  res.send("Hello !!!!");
});

Dalam hal ini Anda membutuhkan kedua fungsi middleware untuk dipanggil. Jadi, satu-satunya cara Anda mencapai fungsi middleware kedua adalah dengan memanggil next ();

Bagaimana jika Anda tidak melakukan panggilan ke berikutnya. Jangan berharap fungsi middleware kedua dipanggil secara otomatis. Setelah menjalankan fungsi pertama, permintaan Anda akan dibiarkan menggantung. Fungsi kedua tidak akan pernah dipanggil dan Anda tidak akan mendapatkan kembali responsnya.


Jadi next()berkinerja seperti gotodengan label terprogram? Artinya, dalam cuplikan ketiga Anda, begitu Anda menelepon next(), res.send("Hello World !!!!"); tidak akan pernah dieksekusi? Saya perhatikan bahwa @Ashe selalu memiliki panggilan return;setelah nextyang memiliki kode di pohon eksekusi yang sama ... Tebak saya selalu bisa hanya memeriksa ekspres, ya? /
Berlari

@ruffin ya Anda bisa memikirkan berikutnya mirip dengan goto. tetapi selanjutnya tahu ke mana harus pergi seperti goto yang membutuhkan label. Selanjutnya akan melewati kontrol ke fungsi middleware berikutnya. Juga, Anda dapat memberi nama 'berikutnya' apa pun yang Anda suka. Ini hanya label di sini. Tetapi praktik terbaik adalah dengan menggunakan nama 'berikutnya'
Mav55

3
Oke, sepertinya itu tidak akurat. Saya mencoba kode ( pastebin di sini ), dan kode setelah next()panggilan dipanggil . Dalam hal ini, past the next() callditulis ke konsol, dan kemudian saya mendapatkan Error: Can't set headers after they are sent.kesalahan, seperti yang kedua res.senddisebut, meskipun tidak berhasil. Alur kode kembali setelah next()panggilan, yang membuat @ Ashe returns(atau manajemen logika lainnya) penting.
ruffin

4
@ruffin, ya kamu benar. Kami membutuhkan pernyataan pengembalian setelah next()untuk melewati eksekusi pernyataan yang tersisa. terima kasih telah menunjukkan itu.
Mav55

1
Terima kasih telah benar-benar menjelaskan apa "middleware" itu / tidak dengan contoh yang jelas dan tidak hanya membeo dokumentasi. Ini adalah satu-satunya jawaban yang benar-benar mengatakan yang jelas tentang apa yang terjadi, mengapa & bagaimana.
mc01


5

Memanggil fungsi ini memanggil fungsi middleware berikutnya dalam aplikasi. Fungsi () berikutnya bukan bagian dari Node.js atau Express API, tetapi argumen ketiga yang diteruskan ke fungsi middleware. Fungsi next () bisa dinamai apa saja, tetapi dengan konvensi itu selalu dinamai “next”.


2

Menjalankan nextfungsi memberitahu server bahwa Anda sudah selesai dengan langkah middleware ini dan dapat menjalankan langkah selanjutnya dalam rantai.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.