如何将Connect中间件组合到一个中间件中?

时间:2013-11-28 20:46:16

标签: node.js connect middleware

我想要将一些中间件合并到一个中间件中。我该怎么做?

例如......

// I want to shorten this...
app.use(connect.urlencoded())
app.use(connect.json())

// ...into this:
app.use(combineMiddleware([connect.urlencoded, connect.json]))

// ...without doing this:
app.use(connect.urlencoded()).use(connect.json())

我希望它能够动态运行 - 我不想依赖我使用的中间件。

我觉得除了令人困惑的for循环之外,还有一个优雅的解决方案。

6 个答案:

答案 0 :(得分:13)

如果您有路径,

Express接受app.use的数组:

var middleware = [connect.urlencoded(), connect.json()];
app.use('/', middleware)

但是,如果您需要通用combineMiddleware函数,则可以轻松构建帮助程序而无需任何其他库。这基本上利用了next只是一个带有可选错误的函数的事实:

/**
 * Combine multiple middleware together.
 *
 * @param {Function[]} mids functions of form:
 *   function(req, res, next) { ... }
 * @return {Function} single combined middleware
 */
function combineMiddleware(mids) {
  return mids.reduce(function(a, b) {
    return function(req, res, next) {
      a(req, res, function(err) {
        if (err) {
          return next(err);
        }
        b(req, res, next);
      });
    };
  });
}

答案 1 :(得分:3)

如果你喜欢花哨的东西,这是一个可能的解决方案:

var connect = require('connect')
var app = connect()

function compose(middleware) {
  return function (req, res, next) {
    connect.apply(null, middleware.concat(next.bind(null, null))).call(null, req, res)
  }
}

function a (req, res, next) {
  console.log('a')
  next()
}

function b (req, res, next) {
  console.log('b')
  next()
}

app.use(compose([a,b]))

app.use(function (req, res) {
  res.end('Hello!')
})

app.listen(3000)

以下是它的作用:compose函数接受中间件数组并返回组合中间件。 connect本身基本上是一个中间件编写器,因此您可以使用所需的中间件创建另一个连接应用程序:connect.apply(null, middleware)。 Connect app本身就是一个中间件,唯一的问题是它最终没有next()调用,因此后续的中间件将无法访问。要解决这个问题,我们需要另一个last中间件,它会调用nextconnect.apply(null, middleware.concat(last))。最后一次只调用next,我们可以使用next.bind(null, null)。最后,我们使用reqres调用结果函数。

答案 2 :(得分:1)

老问题,但是使用中间件的所有事情仍然需要经常,例如连接,快速或定制的req / res / next模式。

这是一个非常优雅且纯粹功能性的解决方案:

文件 ./ utils / compose-middleware.js

function compose(middleware) {
  if (!middleware.length) {
    return function(_req, _res, next) { next(); };
  }

  var head = middleware[0];
  var tail = middleware.slice(1);

  return function(req, res, next) {
    head(req, res, function(err) {
      if (err) return next(err);
      compose(tail)(req, res, next);
    });
  };
}

module.exports = compose;

compose(middlewareList)的最终结果是一个中间件,它封装了最初提供的整个中间件链。

然后只需导入它并使用如下:

档案 app.js

var connect = require('connect');
var compose = require('./utils/compose-middleware');

var middleware = compose([
  connect.urlencoded(),
  connect.json()
]);

var app = connect();
app.use(middleware); 

答案 3 :(得分:0)

如果您愿意使用图书馆:

https://www.npmjs.org/package/middleware-flow

var series = require('middleware-flow').series;
var app = require('express')();

app.use(series(mw1, mw2, mw2)); // equivalent to app.use(mw1, mw2, mw3);

答案 4 :(得分:0)

一种简单而原生的方式,您无需安装任何东西。

const {Router} = require('express')

const combinedMiddleware = Router().use([middleware1, middleware2, middleware3])

然后您可以在需要的地方使用 combinedMiddleware。例如,您可能希望根据某些条件(例如请求属性)为同一路由运行不同的中间件/处理程序集:

app.get('/some-route', (req, res, next) => {
  req.query.someParam === 'someValue'
    ? combinedMiddleware1(req, res, next)
    : combinedMiddleware2(req, res, next)
})

答案 5 :(得分:0)

制作一个列表并使用一个循环。

{
    using System.Text;
    partial class Form1
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV


            System.Text.ASCIIEncoding.ASCIIEncodingSealed asciiEncodingSealed3 = new System.Text.ASCIIEncoding.ASCIIEncoding();


//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

            System.Text.DecoderReplacementFallback decoderReplacementFallback3 = new System.Text.DecoderReplacementFallback();
            System.Text.EncoderReplacementFallback encoderReplacementFallback3 = new System.Text.EncoderReplacementFallback();
            this.port = new System.IO.Ports.SerialPort(this.components);
            this.SuspendLayout();
            // 
            // port
            // 
            this.port.BaudRate = 9600;
            this.port.DataBits = 8;
            this.port.DiscardNull = false;
            this.port.DtrEnable = false;
            asciiEncodingSealed3.DecoderFallback = decoderReplacementFallback3;
            asciiEncodingSealed3.EncoderFallback = encoderReplacementFallback3;
            this.port.Encoding = asciiEncodingSealed3;
            this.port.Handshake = System.IO.Ports.Handshake.None;
            this.port.NewLine = "\n";
            this.port.Parity = System.IO.Ports.Parity.None;
            this.port.ParityReplace = ((byte)(63));
            this.port.PortName = "COM6";
            this.port.ReadBufferSize = 4096;
            this.port.ReadTimeout = -1;
            this.port.ReceivedBytesThreshold = 1;
            this.port.RtsEnable = false;
            this.port.StopBits = System.IO.Ports.StopBits.One;
            this.port.WriteBufferSize = 2048;
            this.port.WriteTimeout = -1;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(484, 461);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
            this.ResumeLayout(false);

        }
        private System.IO.Ports.SerialPort port;
        #endregion
    }
}```

const connect = require('connect') const { urlencoded, json } = require('body-parser') const app = connect() [ urlencoded(), json() ].forEach(app.use, app) 的第二个参数用于 .forEach,但如果您愿意,您也可以这样做:

this