Expressミドルウェアの設計
Express Middleware Design
まだ役に立たないexpress
書かれたserver
最初に、ソースコードのいくつかをもう一度叩きます。
express
エントリファイルlib
フォルダの下express.js
いくつかのメソッドを外の世界に公開しました。
最も重要なexpress.js
36〜47行目):
function createApplication() { var app = function(req, res, next) { App.handle(req, res, next) //Processing entry for each middleware, the handle method is extended to proto by mixin } mixin(app, EventEmitter.prototype, false) mixin(app, proto, false) app.request = { __proto__: req, app: app } app.response = { __proto__: res, app: app } app.init() return app } exports = module.exports = createApplication
私たちはしばしばこれを私たち自身のビジネスコードで書きます:
var express = require('express') var app = express()
実際、それはcreateApplication
メソッドと呼ばれています。これにより、アプリがインスタンス化されます。これはapp
より特別なmixin
他のいくつかのプロパティを統合する
Mixin(app, EventEmitter.prototype, false) //Expanded the event emitter prototype object Mixin(app, proto, false) //Expanded properties and methods in application.js
ビジネスコードでインスタンス化しますapp
呼び出されますapp.init()
メソッドはいくつかの初期構成を完了します。init()
メソッドもfrom application.js
継承されます。
エントリファイルは非常に明確で、主に完了メソッドとapp
いくつかの初期化操作の公開です。
次の外観application.js
次のコードロジックの一部:
行136-146、a _router
のインスタンス化を遅らせる
app.lazyrouter = function lazyrouter() { if (!this._router) { this._router = new Router({ caseSensitive: this.enabled('case sensitive routing'), strict: this.enabled('strict routing') }) this._router.use(query(this.get('query parser fn'))) this._router.use(middleware.init(this)) } }
157〜174行目、これはそれぞれmiddleware
入口、
app.handle = function handle(req, res, callback) { Var router = this._router //Get the router that has been instantiated // final handler var done = callback || finalhandler(req, res, { env: this.get('env'), onerror: logerror.bind(this) }) // no routes if (!router) { debug('no routes defined on app') done() return } Router.handle(req, res, done) //When http comes over, the processing for request and response starts from this place }
行187-242、app.use
メソッドはアプリケーションレベルを提供しますmiddleware
しかし実際には行214で、this.lazyrouter()
新しいルートを作成し、行219-221、そしてapp.use(fn)
パラメータ渡されたものはroute.use()
ルーティングレベルのミドルウェアがオンになっています。app.use()
はいroute.use
エージェント。
app.use = function use(fn) { var offset = 0 var path = '/' // default path to '/' // disambiguate app.use([fn]) if (typeof fn !== 'function') { var arg = fn while (Array.isArray(arg) && arg.length !== 0) { arg = arg[0] } // first arg is the path if (typeof arg !== 'function') { offset = 1 path = fn } } Var fns = flatten(slice.call(arguments, offset)) // flatten the arguments if (fns.length === 0) { throw new TypeError('app.use() requires middleware functions') } // setup router This.lazyrouter() //create a new one if there is no route instance var router = this._router fns.forEach(function (fn) { // non-express app //if the incoming app is not an express instance app if (!fn || !fn.handle || !fn.set) { Return router.use(path, fn) //Inject the middleware into the router } debug('.use app under %s', path) fn.mountpath = path fn.parent = this // restore .app property on req and res router.use(path, function mounted_app(req, res, next) { var orig = req.app fn.handle(req, res, function (err) { req.__proto__ = orig.request res.__proto__ = orig.response next(err) }) }) // mounted an app fn.emit('mount', this) }, this) return this }
行255-258、エージェントto router
インスタンスroute()
メソッド内:
app.route = function route(path) { this.lazyrouter() return this._router.route(path) }
router
インスタンスが渡されますrouter/index.js
このフォルダーに42〜60行目を作成するコンストラクターを提供します。
var proto = module.exports = function(options) { var opts = options || {} function router(req, res, next) { Router.handle(req, res, next) //handle method inherits from proto } // mixin Router class functions router.__proto__ = proto router.params = {} router._params = [] router.caseSensitive = opts.caseSensitive router.mergeParams = opts.mergeParams router.strict = opts.strict Router.stack = [] //Initialize a stack. This stack holds all registered middleware. return router }
提供されたrouter
コンストラクター、そのプロトタイプオブジェクトで、行136が提供されますproto.handle
メソッド、このメソッドの効果は、http
of req
with | _ + _から受け取ることです。 |。
413行目、提供res
メソッド、前述のとおりproto.use
はいapp.use
エージェント、このメソッドの特殊性はいずれかにありますroute.use
リクエストは通過しますhttp
たとえば、ミドルウェアがマウントされましたapp.use
自分から多くのミドルウェアを削除したので、もう一度渡す必要があります。express4.x
インストールして、ビジネスコードで参照してください。たとえばnpm
ミドルウェア:
body-parser
毎回var express = require('express') var app = express() var bodyParser = require('body-parser') app.use(bodyParser.json())
リクエストが来ると、最初に渡されます。http
方向を提供するこのミドルウェアbodyParser.json()
追加req
メソッドと次の役割を渡しますミドルウェア。
同時にreq.body = {}
内部、439〜458行目、
route.use
477行目for (var i = 0 i
proto.route
proto.route = function route(path) { Var route = new Route(path) //Create a new route. The internal implementation of this Route constructor is shown in ./route.js, which provides an empty stack for Var layer = new Layer(path, { // create a new layer, the role of layer see the following explanation sensitive: this.caseSensitive, strict: this.strict, end: true }, route.dispatch.bind(route)) layer.route = route This.stack.push(layer) //Create a new route, this route will maintain its own stack return route }
ですが、この方法は異なります
それは自分自身を維持するということですvar route = require('express').Router()
、これはstack
このメソッドで上記で定義したすべてのミドルウェアがあります。繰り返しますが、これを渡すことができますstack
さまざまなパスのマウントroute
、req
処理。
使用方法:
res
上記の部分は主に全体ですvar express = require('express') var app = express() var router = express.Router() / / No middleware that mounts any path, the middleware will be executed for each request through the route router.use(function(req, res, next) { console.log('route.use') }) router.get('/test', function(req, res, next) { console.log('route.get') }) / / Finally need to mount this router to the application app.use('/', router)
ミドルウェアがマウントされています。結論として:
by
express
マウントされたミドルウェアが最終的に表されます。app.use()
メソッドrouter.use()
メソッド、新しいパスを作成router.use()
、layer
パスは保存され、デフォルトはlayer
および対応する処理メソッドであり、これに格納されます'/'
維持app
in。by
stack
新しく構築されたvar router = require('express').Router()
パスレベルのインスタンスでは、さまざまなミドルウェアをマウントすることもできますが、これを最後に配置する必要があります。router
ルートインジェクションrouter
アプリケーション:app
次に、それについて話しましょうapp.use('/', router)
リクエストが到着すると、データの流れ:ミドルウェアを定義する過程で、ミドルウェアは維持されるためhttp
またはapp
インスタンスには、それぞれにroute
。これはstack
はいstack
したがって、リクエストが着信するたびに、データは最初に定義されたミドルウェアから始まり、順番に渡されるため、自分で定義できます。もちろん、next()メソッドを呼び出す必要があります。ちょうどFIFO
メソッドのように
Route.protoype.dispath
最後に、/ / Req, res distributed to this route Route.prototype.dispatch = function dispatch(req, res, done) { var idx = 0 var stack = this.stack if (stack.length === 0) { return done() } var method = req.method.toLowerCase() if (method === 'head' && !this.methods['head']) { method = 'get' } req.route = this next() function next(err) { if (err && err === 'route') { return done() } var layer = stack[idx++] if (!layer) { return done(err) } If (layer.method && layer.method !== method) { //match the incoming req request method, compared with the layer method return next(err) } / / Call layer.handle for error handling or request processing if (err) { layer.handle_error(err, req, res, next) } else { layer.handle_request(req, res, next) } } }
リクエストの処理:
in http
またはapp
この例では、route
、これはstack
マウントの中央に新しいものを格納しましたstack
それぞれlayer
インスタンスは対応するパスを保存し、対応するlayer
with error_handle
を保存します。
これを見てくれてありがとう、みんなが斧になることを歓迎します。
次の執筆request_handle
ルートの実装。