私が目にするほとんどすべてのExpressアプリにはapp.use
ミドルウェアに関する記述がありますが、実際のミドルウェアとは何か、そのapp.use
記述が何をしているかについての明確で簡潔な説明は見つかりませんでした。エクスプレスドキュメント自体も、これについては少しあいまいです。これらの概念について説明していただけますか?
私が目にするほとんどすべてのExpressアプリにはapp.use
ミドルウェアに関する記述がありますが、実際のミドルウェアとは何か、そのapp.use
記述が何をしているかについての明確で簡潔な説明は見つかりませんでした。エクスプレスドキュメント自体も、これについては少しあいまいです。これらの概念について説明していただけますか?
回答:
新しいプロジェクトでミドルウェアの概念を分離する途中です。
ミドルウェアを使用すると、フローする必要のあるアクションのスタックを定義できます。Expressサーバー自体はミドルウェアのスタックです。
// express
var app = express();
// middleware
var stack = middleware();
次に、呼び出してミドルウェアスタックにレイヤーを追加できます。 .use
// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
next();
});
ミドルウェアスタックのレイヤーは関数で、n個のパラメーター(2つはexpress、req
&res
)とnext
関数を受け取ります。
ミドルウェアは、レイヤーが何らかの計算を行い、パラメーターを増やしてからを呼び出すことを期待していますnext
。
スタックは、処理しない限り何もしません。Expressは、着信HTTP要求がサーバーでキャッチされるたびにスタックを処理します。ミドルウェアでは、スタックを手動で処理します。
// express, you need to do nothing
// middleware
stack.handle(someData);
より完全な例:
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
})
簡単に言うと、すべての着信HTTP要求に対して処理したい一連の操作を定義するだけです。
エクスプレス(接続ではなく)に関しては、グローバルミドルウェアがあり、特定のミドルウェアをルーティングします。つまり、すべての着信HTTPリクエストにミドルウェアスタックをアタッチするか、特定のルートと相互作用するHTTPリクエストにのみミドルウェアスタックをアタッチできます。
エクスプレス&ミドルウェアの高度な例:
// 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);
});
app.use()
構文に少し混乱しています。ミドルウェアの実際の戻り値とは何use
ですか?
以前の回答で言及されていないものを追加するために、遅い回答を追加します。
これで、ミドルウェアがクライアント要求とサーバー応答の間で実行される機能であることは明らかです。必要とされる最も一般的なミドルウェア機能は、エラー管理、データベースの相互作用、静的ファイルまたはその他のリソースからの情報の取得です。ミドルウェアスタックに移動するには、次のコールバックを呼び出す必要があります。ミドルウェア関数の最後でそれを確認して、フローの次のステップに移動できます。
あなたはapp.use
アプローチを使用して、次のようなフローを持つことができます:
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');
ただし、別のアプローチを使用して、各ミドルウェアを関数の引数として渡すこともできます。以下は、MooTools Nodejs Webサイトの例です。ミドルウェアはresponse
、クライアントに送り返される前にTwitter、Github、ブログのフローを取得します。関数が引数としてどのように渡されるかに注意してくださいapp.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
。using app.get
はGETリクエストに対してのみapp.use
呼び出され、すべてのリクエストに対して呼び出されます。
// 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
});
});
.get()
メソッドは3種類の引数を取ります:最初、最後、中間の引数。内部的には、引数が2つ以上あるかどうかを検出し、それら(中央のもの)をミドルウェア関数として使用して、左から右に呼び出します。
expressjs ガイドはあなたの質問にかなりきちんとした答えを持っています、私はそれを読むことを強くお勧めします、私はガイドの短いスニペットを投稿しています、ガイドはかなり良いです。
ミドルウェア関数は、要求オブジェクト( req)、応答オブジェクト( res)、およびアプリケーションの要求-応答サイクルの次の関数にアクセスできる関数です。次の関数はExpressルーターの関数で、呼び出されると、現在のミドルウェアの後継となるミドルウェアを実行します。
ミドルウェア機能は、次のタスクを実行できます。
現在のミドルウェア関数が要求/応答サイクルを終了しない場合、次のミドルウェア関数に制御を渡すためにnext()を呼び出す必要があります。それ以外の場合、リクエストは保留のままになります。
例
以下は、簡単な「Hello World」Expressアプリケーションの例です。この記事の残りの部分では、2つのミドルウェア関数を定義してアプリケーションに追加します。1つは単純なログメッセージを出力するmyLoggerと呼ばれ、もう1つはHTTPリクエストのタイムスタンプを表示するrequestTime 1と呼ばれます。
var express = require('express')
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.listen(3000)
ミドルウェア関数myLogger
以下は、「myLogger」というミドルウェア関数の簡単な例です。この関数は、アプリへのリクエストが通過したときに「LOGGED」を出力するだけです。ミドルウェア関数は、myLoggerという名前の変数に割り当てられます。
var myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
上記のnext()の呼び出しに注意してください。この関数を呼び出すと、アプリ内の次のミドルウェア関数が呼び出されます。次の()関数は、Node.jsのかエクスプレスAPIの一部ではありませんが、ミドルウェアの関数に渡される第三引数です。次の()関数は、自由に名前を付けることができますが、慣例により、常に「次」と命名されます。混乱を避けるために、常にこの規則を使用してください。
ミドルウェア関数をロードするには、ミドルウェア関数を指定してapp.use()を呼び出します。たとえば、次のコードはルートパス(/)へのルートの前にmyLoggerミドルウェア関数をロードします。
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)
アプリはリクエストを受信するたびに、「LOGGED」というメッセージを端末に出力します。
ミドルウェアのロードの順序は重要です。最初にロードされるミドルウェア機能も最初に実行されます。
場合myLoggerは、ルート・パスへのルートの後にロードされ、要求がそれに到達したことがないし、ルートパスのルートハンドラが要求応答サイクルを終了させるためのアプリは、「LOGGED」に印刷されません。
ミドルウェア関数myLoggerは単にメッセージを出力してから、next()関数を呼び出すことにより、スタック内の次のミドルウェア関数に要求を渡します。
=====非常に簡単な説明=====
ミドルウェアはExpress.jsフレームワークのコンテキストで使用されることが多く、node.jsの基本概念です。簡単に言えば、基本的には、アプリケーションの要求オブジェクトと応答オブジェクトにアクセスできる関数です。私がそれについて考えたいのは、アプリケーションによって処理される前にリクエストが通過する一連の「チェック/事前画面」です。たとえば、ミドルウェアは、リクエストがアプリケーションに進む前に認証されているかどうかを判断し、リクエストが認証されていない場合、または各リクエストのロギングにログインページを返すのに適しています。さまざまな機能を実現する多くのサードパーティ製ミドルウェアが利用可能です。
単純なミドルウェアの例:
var app = express();
app.use(function(req,res,next)){
console.log("Request URL - "req.url);
next();
}
上記のコードは、入ってくるリクエストごとに実行され、リクエストのURLを記録します。next()メソッドは基本的にプログラムの続行を許可します。next()関数が呼び出されない場合、プログラムはそれ以上処理せず、ミドルウェアの実行で停止します。
いくつかのミドルウェアの問題点:
next()
けどreturn next()
。違いはなんですか?
next()
私たちが次のミドルウェアが呼び出さたいので、私は考えていないnext()
かreturn next()
、任意の違いを作る必要があります!それでも、コードが何であるかによって異なります...
ミドルウェアは、入力/ソースが出力を生成した後、途中で実行される関数であり、最終出力になるか、サイクルが完了するまで次のミドルウェアで使用されます。
これは、組み立てラインを通過する製品のようなものであり、完了するか、評価されるか、拒否されるまで、移動するにつれて修正されます。
ミドルウェアは、何らかの値が機能することを期待し(つまり、パラメーター値)、いくつかのロジックに基づいて、ミドルウェアは次のミドルウェアを呼び出すか呼び出さないか、クライアントに応答を返します。
それでもミドルウェアの概念を理解できない場合は、DecoratorまたはChain of commandパターンに似ています。
物事をシンプルにしてください!
注:答えはExpressJS組み込みミドルウェアのケースに関連していますが、ミドルウェアの定義と使用例は異なります。
私の観点から見ると、ミドルウェアはユーティリティまたはヘルパー機能として機能しますが、app.use('path', /* define or use builtin middleware */)
クライアントの各HTTPリクエストに必要な非常に一般的なタスクを実行するためのコードを記述したくないものを使用することで、ミドルウェアのアクティブ化と使用は完全にオプションですほとんどのアプリケーションで非常に一般的なCookie、CSRFトークンなどの処理のように、ミドルウェアは、いくつかのスタック、シーケンス、または操作の順序でクライアントのHTTPリクエストごとにこれらすべてを実行するのに役立ち、プロセスの結果を次のように提供します。クライアント要求の単一ユニット。
例:
クライアントの要求を受け入れ、その要求に応じてクライアントに応答を返すことは、Webサーバーテクノロジーの性質です。
「Hello、world!」だけで応答を提供していると想像してみてください。WebサーバーのルートURIへのGET HTTPリクエストのテキストは非常に単純なシナリオであり、他に何も必要ありませんが、代わりに現在ログインしているユーザーを確認してから「Hello、Username!」で応答する場合 この場合、通常以上のものが必要です。すべてのクライアント要求メタデータを処理し、クライアント要求から取得した識別情報を提供するミドルウェアが必要です。その情報に従って、現在のユーザーを一意に識別でき、彼に応答することができます。 /彼女といくつかの関連データ。
それが誰かを助けることを願っています!
非常に基本的な用語で、このように説明したい場合は、traversymedia youtubeチャンネルエクスプレスクラッシュコースからこれを学びます。
わかりましたので、ミドルウェアは、このようにルートを呼び出した後に実行される関数です。
var logger = function(req, res, next){
console.log('logging...');
next();
}
app.use(logger);
このロガー関数は、ページを更新するたびに実行されます。つまり、ページに操作api呼び出しがレンダリングされた後、必要なことを何でも書き込むことができ、基本的にすべてをリセットします。このミドルウェアをミドルウェアのルート機能の順序の前に置くと、ミドルウェアが非常に重要になるか、機能しなくなります。