Шаблон промежуточного программного обеспечения Node.js

Node.js внешний интерфейс Шаблоны проектирования Express

промежуточное ПОШироко используемый в Node.js, он обычно относится к определенному шаблону проектирования, ряду блоков обработки, фильтров и обработчиков в виде функций, соединенных вместе для формирования асинхронной очереди для завершения любой предварительной обработки и постобработки данных.

Его преимущество в том, чтогибкость: С помощью промежуточного программного обеспечения мы получаем плагин с минимальными операциями, самый простой способ расширить новые фильтры и обработчики на существующую систему.

Обычный шаблон промежуточного ПО

В шаблоне промежуточного программного обеспечения самым основным компонентом являетсяменеджер промежуточного программного обеспечения, мы можем использовать его для организации и выполнения функций промежуточного программного обеспечения, как показано ниже:

中间件.jpg

Для реализации шаблона промежуточного программного обеспечения наиболее важными деталями реализации являются:

  • позвонивuse()функция для регистрации нового промежуточного программного обеспечения.Обычно новое промежуточное программное обеспечение может быть добавлено только в конец высоковольтного пакета, но это не является строго обязательным;
  • При получении новых данных, которые необходимо обработать, зарегистрированное промежуточное ПО последовательно вызывается в неисполняемом процессе. Каждое промежуточное ПО принимает результат выполнения предыдущего промежуточного ПО в качестве входного значения;
  • Каждое промежуточное ПО может остановить дальнейшую обработку данных, просто не вызывая свою функцию уничтожения или передавая ошибку функции обратного вызова. Когда возникает ошибка, она обычно инициирует выполнение другого промежуточного программного обеспечения, которое специализируется на обработке ошибок.

Что касается того, как поступать с передачей данных, то строгих правил на данный момент нет, в общем, есть несколько способов.

  • Улучшено добавлением свойств и методов;
  • заменить данные результатом некоторой обработки;
  • Исходные данные, подлежащие обработке, гарантированно остаются неизменными, а в качестве результата обработки всегда возвращается новая копия.

Специальный метод лечения зависит отменеджер промежуточного программного обеспеченияреализация и тип задач, которые должно выполнять само промежуточное ПО.

Возьмите один изШаблоны проектирования Node.js, второе изданиеРеализация библиотеки обмена сообщениямименеджер промежуточного программного обеспеченияпример:

class ZmqMiddlewareManager {
    constructor(socket) {
        this.socket = socket;
        // 两个列表分别保存两类中间件函数:接受到的信息和发送的信息。
        this.inboundMiddleware = [];
        this.outboundMiddleware = [];
        socket.on('message', message => {
            this.executeMiddleware(this.inboundMiddleware, {
                data: message
            });
        });
    }
    
    send(data) {
        const message = { data };
        
        this.excuteMiddleware(this.outboundMiddleware, message, () => {
            this.socket.send(message.data);
        });
    }
    
    use(middleware) {
        if(middleware.inbound) {
            this.inboundMiddleware.push(middleware.inbound);
        }
        if(middleware.outbound) {
            this.outboundMiddleware.push(middleware.outbound);
        }
    }
    
    exucuteMiddleware(middleware, arg, finish) {
        function iterator(index) {
            if(index === middleware.length) {
                return finish && finish();
            }
            middleware[index].call(this, arg, err => {
                if(err) {
                    return console.log('There was an error: ' + err.message);
                }
                iterator.call(this, ++index);
            });
        }
        iterator.call(this, 0);
    }
}

Далее нужно только создать middleware, соответственно вinboundа такжеoutboundНапишите функцию промежуточного программного обеспечения в функции промежуточного программного обеспечения, а затем вызовите ее после выполнения.next()Достаточно. Например:

const zmqm = new ZmqMiddlewareManager();

zmqm.use({
    inbound: function(message, next) {
        console.log('input message: ', message.data);
        next();
    },
    outbound: function(message, next) {
        console.log('output message: ', message.data);
        next();
    }
});

Рекламируется Экспресспромежуточное ПОКонцепция похожа, промежуточное ПО Express обычно выглядит так:

function(req, res, next) { ... }

Промежуточное ПО, используемое в Koa2

Модель промежуточного программного обеспечения, показанная ранее, реализована с использованием функций обратного вызова, но теперь есть более модный фреймворк Node.js.Koa2Реализация промежуточного программного обеспечения несколько отличается от описанной ранее.Koa2Первоначально использовался шаблон промежуточного программного обеспечения в удаленномES2015Метод, реализованный генератором в , совместим с функциями обратного вызова,convertпост генератор иasyncа такжеawait.

существуетKoa2Официальная документация дает описание промежуточного программного обеспечения.луковая модель,Как показано ниже:

koa中间件.jpg

Из рисунка видно, что первыйinboundФункция промежуточного программного обеспечения находится вoutboundЕго положили в спину и казнили, так почему? Имея в виду этот вопрос, давайте прочитаемKoa2исходный код.

существуетkoa/lib/applications.js, сначала посмотрите на конструктор, а на остальное можете не обращать внимания, ключthis.middleware,этоinboundочередь:

constructor() {
    super();

    this.proxy = false;
    this.middleware = [];
    this.subdomainOffset = 2;
    this.env = process.env.NODE_ENV || 'development';
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
}

Как и выше, вKoa2также используется вuse()Чтобы поставить промежуточное ПО в очередь:

use(fn) {
    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
    if (isGeneratorFunction(fn)) {
        deprecate('Support for generators will be removed in v3. ' +
                'See the documentation for examples of how to convert old middleware ' +
                'https://github.com/koajs/koa/blob/master/docs/migration.md');
        fn = convert(fn);
    }
    debug('use %s', fn._name || fn.name || '-');
    this.middleware.push(fn);
    return this;
}

Затем мы смотрим, как фреймворк монитора порта был простым пакетом:

// 封装之前 http.createServer(app.callback()).listen(...)
listen(...args) {
    debug('listen');
    const server = http.createServer(this.callback());
    return server.listen(...args);
}

Ключ к управлению промежуточным ПО лежит вthis.callback(), взгляните на этот метод:

callback() {
    const fn = compose(this.middleware);
    
    if (!this.listenerCount('error')) this.on('error', this.onerror);
    
    const handleRequest = (req, res) => {
        const ctx = this.createContext(req, res);
        return this.handleRequest(ctx, fn);
    };
    
    return handleRequest;
}

здесьcomposeМетод на самом делеKoa2основной модульkoa-compose(https://github.com/koajs/compose), в этом модуле инкапсулирован метод выполнения промежуточного ПО:

function compose (middleware) {
    if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
    for (const fn of middleware) {
        if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
    }
    
      /**
       * @param {Object} context
       * @return {Promise}
       * @api public
       */
    
    return function (context, next) {
        // last called middleware #
        let index = -1
        return dispatch(0)
        function dispatch (i) {
            if (i <= index) return Promise.reject(new Error('next() called multiple times'))
            index = i
            let fn = middleware[i]
            if (i === middleware.length) fn = next
            if (!fn) return Promise.resolve()
            try {
                return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
            } catch (err) {
                return Promise.reject(err)
            }
        }
    }
}

можно увидеть,composeОчередь промежуточного ПО выполняется рекурсивноОбход в обратном порядке, который генерируетPromiseцепочка, далее просто нужно позвонитьPromiseФункцию промежуточного программного обеспечения можно выполнить:

handleRequest(ctx, fnMiddleware) {
    const res = ctx.res;
    res.statusCode = 404;
    const onerror = err => ctx.onerror(err);
    const handleResponse = () => respond(ctx);
    onFinished(res, onerror);
    return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}

Его можно найти в исходном коде,next()возвращеноPromise, поэтому общее промежуточное ПО записывается так:

app.use((ctx, next) => {
    const start = new Date();
    return next().then(() => {
        const ms = new Date() - start;
        console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
    });
});

Конечно, если вы используетеasyncа такжеawaitтакже:

app.use((ctx, next) => {
    const start = new Date();
    await next();
    const ms = new Date() - start;
    console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});

Так как есть многоKoa1Промежуточное ПО проекта основано на генераторе и должно использоватьkoa-convertДля выполнения плавного обновления:

const convert = require('koa-convert');

app.use(convert(function *(next) {
    const start = new Date();
    yield next;
    const ms = new Date() - start;
    console.log(`${this.method} ${this.url} - ${ms}ms`);
}));

Наконец, если вы считаете, что статья полезна, пожалуйста, поставьте мне палец вверх! Если вы обнаружите какие-либо ошибки, пожалуйста, не стесняйтесь сообщать о них!