Middleware và app.use thực sự có ý nghĩa gì trong Expressjs?


228

Hầu như mọi ứng dụng Express mà tôi thấy đều có một app.usetuyên bố cho phần mềm trung gian nhưng tôi không tìm thấy lời giải thích rõ ràng, ngắn gọn về phần mềm trung gian thực sự là gì và app.usecâu lệnh đó đang làm gì. Ngay cả bản thân các tài liệu thể hiện cũng hơi mơ hồ về điều này. Bạn có thể giải thích những khái niệm này cho tôi xin vui lòng?


3
câu hỏi tương tự để tham khảo (tho cái này đã được tạo trước đó): stackoverflow.com/questions/11321635/
mẹo

43
^ Hà! Hai câu hỏi tham khảo lẫn nhau trong các ý kiến.
Julian H. Lam

17
Vì vậy, nó là một tài liệu tham khảo Cirular.
Steve K

6
Express.js Middleware Demystified Một bài đăng blog tuyệt vời về chủ đề này. Điều này đã được sao chép ở đây trước đây, đó là đạo văn tất nhiên, nhưng bài viết gốc vẫn thực sự hữu ích vì vậy tôi để lại một liên kết ở đây.
totymedli

1
Tôi đã viết một bài viết về phần mềm trung gian express.js. Đây là đường dẫn: gậtxplained.com/blog
detail/2017/12/31/iêu

Câu trả lời:


111

phần mềm trung gian

Tôi đang phân nửa khái niệm phần mềm trung gian trong một dự án mới.

Middleware cho phép bạn xác định một chồng các hành động mà bạn nên thực hiện. Bản thân các máy chủ Express là một chồng các phần mềm trung gian.

// express
var app = express();
// middleware
var stack = middleware();

Sau đó, bạn có thể thêm các lớp vào ngăn xếp phần mềm trung gian bằng cách gọi .use

// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
  next();
});

Một lớp trong ngăn xếp phần mềm trung gian là một hàm, có n tham số (2 cho express, req& res) và một nexthàm.

Middleware hy vọng lớp sẽ thực hiện một số tính toán, tăng các tham số và sau đó gọi next.

Một ngăn xếp không làm gì cả trừ khi bạn xử lý nó. Express sẽ xử lý ngăn xếp mỗi khi yêu cầu HTTP đến được bắt gặp trên máy chủ. Với phần mềm trung gian, bạn xử lý ngăn xếp bằng tay.

// express, you need to do nothing
// middleware
stack.handle(someData);

Một ví dụ đầy đủ hơn:

var middleware = require("../src/middleware.js");

var stack = middleware(function(data, next) {
    data.foo = data.data*2;
    next();
}, function(data, next) {
    setTimeout(function() {
        data.async = true;
        next();
    }, 100)
}, function(data) {
    console.log(data);
});

stack.handle({
    "data": 42
})

Theo thuật ngữ rõ ràng, bạn chỉ cần xác định một chồng các hoạt động mà bạn muốn express xử lý cho mọi yêu cầu HTTP đến.

Về mặt thể hiện (chứ không phải kết nối), bạn có phần mềm trung gian toàn cầu và định tuyến phần mềm trung gian cụ thể. Điều này có nghĩa là bạn có thể đính kèm một ngăn xếp phần mềm trung gian cho mọi yêu cầu HTTP đến hoặc chỉ đính kèm nó với các yêu cầu HTTP tương tác với một tuyến đường nhất định.

Các ví dụ nâng cao về express & middleware:

// middleware 

var stack = middleware(function(req, res, next) {
    users.getAll(function(err, users) {
        if (err) next(err);
        req.users = users;
        next();  
    });
}, function(req, res, next) {
    posts.getAll(function(err, posts) {
        if (err) next(err);
        req.posts = posts;
        next();
    })
}, function(req, res, next) {
    req.posts.forEach(function(post) {
        post.user = req.users[post.userId];
    });

    res.render("blog/posts", {
        "posts": req.posts
    });
});

var app = express.createServer();

app.get("/posts", function(req, res) {
   stack.handle(req, res); 
});

// express

var app = express.createServer();

app.get("/posts", [
    function(req, res, next) {
        users.getAll(function(err, users) {
            if (err) next(err);
            req.users = users;
            next();  
        });
    }, function(req, res, next) {
        posts.getAll(function(err, posts) {
            if (err) next(err);
            req.posts = posts;
            next();
        })
    }, function(req, res, next) {
        req.posts.forEach(function(post) {
            post.user = req.users[post.userId];
        });

        res.render("blog/posts", {
            "posts": req.posts
        });
    }
], function(req, res) {
   stack.handle(req, res); 
});

4
Hmm ... là phần mềm trung gian trong trường hợp này là thư viện của riêng bạn hoặc một phần của express?
iZ.

5
Mát mẻ. Tôi vẫn còn một chút bối rối bởi app.use()cú pháp. Giá trị trả lại thực tế của phần mềm trung gian là gì và uselàm gì với nó?
iZ.

9
@iZ sử dụng thêm nó vào một ngăn xếp. Sau đó, mỗi yêu cầu đi qua ngăn xếp.
Raynos

7
@Raynos, liên kết đến dự án của bạn, "phần mềm trung gian", đã bị hỏng.
Lee

1
@Raynos nhưng tôi thấy phần mềm trung gian vẫn đang được sử dụng trong Express? ý bạn là gì?
Timo Huovinen

60

Sau khi đơn giản hóa mọi thứ, một máy chủ web có thể được xem như là một chức năng nhận yêu cầu và đưa ra phản hồi. Vì vậy, nếu bạn xem một máy chủ web là một chức năng, bạn có thể sắp xếp nó thành nhiều phần và tách chúng thành các chức năng nhỏ hơn để thành phần của chúng sẽ là chức năng ban đầu.

Middleware là các chức năng nhỏ hơn mà bạn có thể sáng tác với người khác và lợi ích rõ ràng là bạn có thể sử dụng lại chúng.


33

Tôi thêm một câu trả lời muộn để thêm một cái gì đó không được đề cập trong các câu trả lời trước.

Bây giờ, rõ ràng là phần mềm trung gian là / là các hàm chạy giữa yêu cầu máy kháchcâu trả lời của máy chủ . Chức năng phần mềm trung gian phổ biến nhất cần có là quản lý lỗi, tương tác cơ sở dữ liệu, nhận thông tin từ các tệp tĩnh hoặc các tài nguyên khác. Để di chuyển trên ngăn xếp phần mềm trung gian, cuộc gọi lại tiếp theo phải được gọi, bạn có thể thấy nó ở cuối chức năng phần mềm trung gian để chuyển sang bước tiếp theo trong luồng.

Bạn có thể sử dụng app.usecách tiếp cận và có một luồng như thế này :

var express = require('express'),
    app = express.createServer(),                                                                                                                                                 
    port = 1337;

function middleHandler(req, res, next) {
    console.log("execute middle ware");
    next();
}

app.use(function (req, res, next) {
    console.log("first middle ware");                                                                                                             
    next();
});

app.use(function (req, res, next) {
    console.log("second middle ware");                                                                                                             
    next();
});

app.get('/', middleHandler, function (req, res) {
    console.log("end middleware function");
    res.send("page render finished");
});

app.listen(port);
console.log('start server');

nhưng bạn cũng có thể sử dụng một cách tiếp cận khác và chuyển từng phần mềm trung gian làm đối số hàm. Dưới đây là một ví dụ từ trang web MooTools Nodejs nơi midleware có được luồng Twitter, Github và Blog trước khi responseđược gửi lại cho khách hàng. Lưu ý cách các hàm được truyền dưới dạng đối số trong app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){. Sử dụng app.getsẽ chỉ được gọi cho các yêu cầu GET, app.usesẽ được gọi cho tất cả các yêu cầu.

// github, twitter & blog feeds
var githubEvents = require('./middleware/githubEvents')({
    org: 'mootools'
});
var twitter = require('./middleware/twitter')();
var blogData = require('./blog/data');
function getLatestBlog(req, res, next){
    blogData.get(function(err, blog) {
        if (err) next(err);
        res.locals.lastBlogPost = blog.posts[0];
        next();
    });
}

// home
app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
    res.render('index', {
        title: 'MooTools',
        site: 'mootools',
        lastBlogPost: res.locals.lastBlogPost,
        tweetFeed: res.locals.twitter
    });
});

2
Tôi đang tìm kiếm một câu trả lời cho việc Express.js có hỗ trợ việc gắn phần mềm trung gian dựa trên tuyến đường (KHÔNG dựa trên Bộ định tuyến) không? Có vẻ như bạn đã cho thấy nó trong câu trả lời của bạn.
Selçuk

Bạn có thể giải thích ví dụ trên của bạn không? Làm thế nào bạn có thể chuyển nhiều chức năng vào app.get (...) và chúng được gọi theo thứ tự nào?
Tanner Summers

2
Xin chào @TannerSummers, .get()phương thức này có 3 loại đối số: đầu tiên, cuối cùng và giữa. Trong nội bộ, nó phát hiện nếu có nhiều đối số hơn 2 và sử dụng các đối số (phần giữa) làm các hàm phần mềm trung gian, gọi chúng từ trái sang phải.
Sergio

22

expressjs dẫn có câu trả lời khá gọn gàng cho câu hỏi của bạn, tôi khuyên bạn nên đọc nó, tôi đang đăng một đoạn ngắn của hướng dẫn, hướng dẫn khá tốt.

Viết phần mềm trung gian để sử dụng trong ứng dụng Express

Tổng quat

Các hàm Middleware là các hàm có quyền truy cập vào đối tượng yêu cầu ( req ), đối tượng phản hồi ( res ) và chức năng tiếp theo trong chu trình đáp ứng yêu cầu của ứng dụng. Chức năng tiếp theo là một chức năng trong bộ định tuyến Express, khi được gọi, sẽ thực thi phần mềm trung gian kế tiếp phần mềm trung gian hiện tại.

Các hàm Middleware có thể thực hiện các tác vụ sau:

  • Thực thi bất kỳ mã.
  • Thay đổi yêu cầu và các đối tượng phản hồi.
  • Kết thúc chu trình đáp ứng yêu cầu.
  • Gọi phần mềm trung gian tiếp theo trong ngăn xếp.

Nếu chức năng phần mềm trung gian hiện tại không kết thúc chu kỳ đáp ứng yêu cầu, nó phải gọi next () để chuyển điều khiển sang chức năng phần mềm trung gian tiếp theo. Nếu không, yêu cầu sẽ được treo lại.

nhập mô tả hình ảnh ở đây

Thí dụ

Dưới đây là một ví dụ về ứng dụng đơn giản của Hello Hello World. Phần còn lại của bài viết này sẽ xác định và thêm hai hàm phần mềm trung gian vào ứng dụng: một hàm gọi là myLogger in một thông điệp tường trình đơn giản và một hàm khác gọi là requestTime 1 hiển thị dấu thời gian của yêu cầu HTTP.

var express = require('express')
var app = express()

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

app.listen(3000)   

Middleware chức năng myLogger

Dưới đây là một ví dụ đơn giản về một chức năng phần mềm trung gian có tên là my mygerger. Chức năng này chỉ in In LOGGED trực tiếp khi có yêu cầu đến ứng dụng. Hàm phần mềm trung gian được gán cho một biến có tên myLogger.

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

Lưu ý cuộc gọi ở trên để tiếp theo () . Gọi chức năng này gọi chức năng trung gian tiếp theo trong ứng dụng. Hàm next () không phải là một phần của Node.js hoặc Express API, nhưng là đối số thứ ba được truyền cho hàm phần mềm trung gian. Hàm next () có thể được đặt tên bất cứ thứ gì, nhưng theo quy ước, nó luôn được đặt tên là tiếp theo. Để tránh nhầm lẫn, luôn luôn sử dụng quy ước này.

Để tải chức năng phần mềm trung gian, hãy gọi app.use () , chỉ định chức năng phần mềm trung gian. Ví dụ, đoạn mã sau tải chức năng phần mềm trung gian myLogger trước khi định tuyến đến đường dẫn gốc (/).

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

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

app.listen(3000)

Mỗi khi ứng dụng nhận được yêu cầu, nó sẽ in thông báo LOG LOGEDED đến thiết bị đầu cuối.

Thứ tự tải phần mềm trung gian rất quan trọng: các chức năng phần mềm trung gian được tải trước cũng được thực hiện trước.

Nếu myLogger được tải sau khi định tuyến đến đường dẫn gốc, yêu cầu không bao giờ đến được và ứng dụng không in ra LOGGEDED, bởi vì trình xử lý tuyến đường của đường dẫn gốc chấm dứt chu kỳ phản hồi yêu cầu.

Hàm phần mềm trung gian myLogger chỉ cần in một thông báo, sau đó chuyển yêu cầu đến hàm phần mềm trung gian tiếp theo trong ngăn xếp bằng cách gọi hàm next () .


  1. Bài đăng này sẽ chỉ chứa phần mềm trung gian myLogger, để biết thêm bài viết bạn có thể đi đến hướng dẫn expressjs ban đầu ở đây .


1
Giải thích rất hay.
Drumbeg

Nó có sẵn trên trang web express ở đây expressjs.com/en/guide/wr-middleware.html , nó thực sự tốt. Tôi tự hỏi tại sao không ai đề cập đến nó cho đến nay.
Suraj Jain

2
Đẹp một. Đó là lời giải thích rõ ràng nhất mà tôi đã thấy ở đây và vâng, thật lạ khi không ai nhắc đến nó!
Drumbeg

1
Giải thích độc đáo
Rehan Shikkalgar

Thứ tự tải phần mềm trung gian rất quan trọng: các chức năng phần mềm trung gian được tải trước cũng được thực hiện trước. : Đây là một lưu ý quan trọng. Không có câu trả lời khác đề cập đến điều này. Đối với một người mới bắt đầu chỉ làm việc với trăn, điều này cực kỳ quan trọng vì những điều này có thể chưa bao giờ gặp phải.
Tessaracter

11

===== Giải thích rất đơn giản =====

Middleware thường được sử dụng trong ngữ cảnh của khung Express.js và là một khái niệm cơ bản cho node.js. Tóm lại, về cơ bản, đây là một chức năng có quyền truy cập vào các đối tượng yêu cầu và phản hồi của ứng dụng của bạn. Cách tôi muốn nghĩ về nó, là một loạt 'kiểm tra / sàng lọc trước' mà yêu cầu phải thực hiện trước khi ứng dụng được xử lý. Ví dụ: Middlewares sẽ phù hợp để xác định xem yêu cầu có được xác thực hay không trước khi tiến hành ứng dụng và trả lại trang đăng nhập nếu yêu cầu không được xác thực hoặc đăng nhập từng yêu cầu. Rất nhiều phần mềm trung gian của bên thứ ba có sẵn cho phép nhiều chức năng.

Ví dụ Middleware đơn giản:

var app = express();
app.use(function(req,res,next)){
    console.log("Request URL - "req.url);
    next();
}

Đoạn mã trên sẽ được thực thi cho từng yêu cầu xuất hiện và sẽ ghi lại url yêu cầu, phương thức () tiếp theo về cơ bản cho phép chương trình tiếp tục. Nếu hàm next () không được gọi, chương trình sẽ không tiếp tục và sẽ tạm dừng khi thực hiện phần mềm trung gian.

Một vài Middleware Gotchas:

  1. Thứ tự của các phần mềm trung gian trong ứng dụng của bạn có vấn đề, vì yêu cầu sẽ đi qua từng cái theo thứ tự tuần tự.
  2. Việc quên gọi phương thức next () trong hàm phần mềm trung gian của bạn có thể ngăn quá trình xử lý yêu cầu của bạn.
  3. Bất kỳ thay đổi đối tượng req và res trong chức năng phần mềm trung gian, sẽ làm cho thay đổi có sẵn cho các phần khác của ứng dụng sử dụng req và res

1
Cảm ơn rât nhiều! đây là lời giải thích tốt nhất cho đến nay để hiểu điều này. Một câu hỏi, tôi đang đọc một số mã với phần mềm trung gian và nó không gọi next()nhưng return next(). Sự khác biệt là gì?
KansaiRobot

Cảm ơn rất nhiều người bạn vì những lời tốt đẹp ... chúng tôi làm next()vì chúng tôi muốn phần mềm trung gian tiếp theo được gọi, tôi không nghĩ next()hoặc return next(), nên tạo ra bất kỳ sự khác biệt nào! Tuy nhiên, nó phụ thuộc vào mã là gì ...
Vaibhav Bacchav

7

Middleware là các hàm được thực thi ở giữa sau đầu vào / nguồn sau đó tạo ra một đầu ra có thể là đầu ra cuối cùng hoặc có thể được sử dụng bởi phần mềm trung gian tiếp theo cho đến khi chu trình hoàn tất.

Nó giống như một sản phẩm đi qua một dây chuyền lắp ráp, nơi nó được sửa đổi khi nó di chuyển cho đến khi nó được hoàn thành, đánh giá hoặc bị từ chối.

Một phần mềm trung gian mong đợi một số giá trị hoạt động (tức là các giá trị tham số) và dựa trên một số logic, phần mềm trung gian sẽ gọi hoặc không gọi phần mềm trung gian tiếp theo hoặc gửi phản hồi lại cho máy khách.

Nếu bạn vẫn không thể nắm bắt được khái niệm phần mềm trung gian, thì đó là một cách tương tự như Trình trang trí hoặc Chuỗi các mẫu lệnh.


5

Middleware là một tập hợp con của các hàm được xâu chuỗi được gọi bởi lớp định tuyến Express js trước khi trình xử lý do người dùng định nghĩa được gọi. Các hàm Middleware có quyền truy cập đầy đủ vào các đối tượng yêu cầu và phản hồi và có thể sửa đổi một trong hai đối tượng đó.

Chuỗi phần mềm trung gian luôn được gọi theo thứ tự chính xác mà nó đã được xác định, vì vậy điều quan trọng là bạn phải biết chính xác một phần cụ thể của phần mềm trung gian đang làm gì.
Khi một chức năng phần mềm trung gian kết thúc, nó gọi hàm tiếp theo trong chuỗi bằng cách gọi đối số tiếp theo của nó là hàm.
Sau khi chuỗi hoàn chỉnh được thực thi, trình xử lý yêu cầu người dùng được gọi.


1

Giữ mọi thứ đơn giản, anh bạn!

Ghi chú: câu trả lời có liên quan đến các trường hợp trung gian tích hợp sẵn ExpressJS, tuy nhiên có các định nghĩa và trường hợp sử dụng khác nhau của phần mềm trung gian.

Theo quan điểm của tôi, phần mềm trung gian hoạt động như các chức năng của tiện ích hoặc trợ giúp nhưng việc kích hoạt và sử dụng nó hoàn toàn là tùy chọn bằng cách sử dụng cái app.use('path', /* define or use builtin middleware */)mà chúng tôi không muốn viết một số mã để thực hiện các tác vụ rất phổ biến cần thiết cho mỗi yêu cầu HTTP của khách hàng như xử lý cookie, mã thông báo CSRF và ..., rất phổ biến trong hầu hết các ứng dụng, vì vậy phần mềm trung gian có thể giúp chúng tôi thực hiện tất cả các yêu cầu HTTP của khách hàng trong một số ngăn xếp, chuỗi hoặc thứ tự các hoạt động sau đó cung cấp kết quả của quy trình như một đơn vị yêu cầu của khách hàng .

Thí dụ:

Chấp nhận các yêu cầu của khách hàng và cung cấp phản hồi lại cho họ theo yêu cầu của họ là bản chất của công nghệ máy chủ web.

Hãy tưởng tượng nếu chúng tôi cung cấp một phản hồi chỉ với "Xin chào, thế giới!" văn bản cho yêu cầu GET HTTP đến URI gốc của máy chủ web của chúng tôi là kịch bản rất đơn giản và không cần bất cứ điều gì khác, nhưng thay vào đó, nếu chúng tôi đang kiểm tra người dùng đang đăng nhập và sau đó trả lời bằng "Xin chào, Tên người dùng!" cần một cái gì đó nhiều hơn bình thường trong trường hợp này, chúng tôi cần một phần mềm trung gian để xử lý tất cả siêu dữ liệu yêu cầu của khách hàng và cung cấp cho chúng tôi thông tin nhận dạng được lấy từ yêu cầu của khách hàng, theo thông tin đó, chúng tôi có thể xác định duy nhất người dùng hiện tại của mình và có thể phản hồi cho anh ta / cô ấy với một số dữ liệu liên quan.

Hy vọng nó sẽ giúp được ai đó!


-1

Trong thuật ngữ rất cơ bản nếu tôi muốn giải thích nó như thế này, tôi học điều này từ khóa học chuyển phát nhanh trên kênh youtube của traversymedia.
ok vậy, Middle ware là một chức năng thực thi sau khi bạn thực hiện cuộc gọi đến tuyến đường của bạn như thế này.

var logger = function(req, res, next){
   console.log('logging...');
   next();
}

app.use(logger);

Hàm logger này thực thi mỗi khi bạn làm mới trang của mình, điều đó có nghĩa là bạn có thể viết bất cứ điều gì trong đó mà bạn cần phải làm sau khi trang của bạn được thực hiện bất kỳ cuộc gọi api hoạt động nào, thiết lập lại mọi thứ về cơ bản mọi thứ. và đặt phần mềm trung gian này trước khi thứ tự chức năng tuyến đường của bạn thực sự quan trọng hoặc nó không hoạt động

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.