Узел.js / Express.js-как переопределить / перехватить res.функция рендеринга?

Я создаю узел.js приложение с Connect / Express.мы с Джей Си хотим перехватить резервацию.функция render (view, option) для запуска некоторого кода перед его пересылкой в исходную функцию render.

app.get('/someUrl', function(req, res) {

    res.render = function(view, options, callback) {
        view = 'testViews/' + view;
        res.prototype.render(view, options, callback);
    };

    res.render('index', { title: 'Hello world' });
});

это выглядит как надуманный пример, но он вписывается в общую систему я строю.

мое знание ООП и прототипного наследования на JavaScript немного слабое. Как я могу сделать что-то подобное?


обновление: После некоторых экспериментов я пришел к следующему:

app.get('/someUrl', function(req, res) {

    var response = {};

    response.prototype = res;

    response.render = function(view, opts, fn, parent, sub){
        view = 'testViews/' + view;
        this.prototype.render(view, opts, fn, parent, sub);
    };

    response.render('index', { title: 'Hello world' });
});

Это, кажется, работает. Не уверен, что это лучшее решение, поскольку я создаю новый объект оболочки ответа для каждого запроса, это будет проблемой?

4 ответов


старый вопрос, но обнаружил, что задаю то же самое. Как перехватить рендеринг res? Использование express 4.0 x что-то сейчас.

вы можете использовать/писать промежуточного. Поначалу эта концепция меня немного пугала, но после некоторого чтения она стала более осмысленной. И просто для некоторого контекста для тех, кто еще читает это, мотивация для переопределения res.render должен был предоставить переменные глобального представления. Я хочу!--3--> быть доступным во всех моих шаблонах без необходимости вводить его в каждом объект РЭС.

основной формат промежуточного программного обеспечения.

app.use( function( req, res, next ) {
    //....
    next();
} );

следующий вызов param и функции имеют решающее значение для выполнения. next - это функция обратного вызова, чтобы позволить нескольким промежуточным делать свое дело без блокировки. Для лучшего объяснение читайте здесь

Это может быть использовано для переопределения логики рендеринга

app.use( function( req, res, next ) {
    // grab reference of render
    var _render = res.render;
    // override logic
    res.render = function( view, options, fn ) {
        // do some custom logic
        _.extend( options, {session: true} );
        // continue with original render
        _render.call( this, view, options, fn );
    }
    next();
} );

я протестировал этот код, используя express 3.0.6. Он должен работать с 4.х без проблем. Также можно переопределить конкретные URL-адреса комбо с

app.use( '/myspcificurl', function( req, res, next ) {...} );

на


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

Как вы знаете, javascript-это язык, основанный на прототипе, и каждый объект имеет прототип, например объекты response и request. Глядя на код (экспресс-4.13.4) вы можете найти их прототипы:

req => express.request
res => express.response

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

var app = (global.express = require('express'))();
var render = express.response.render;
express.response.render = function(view, options, callback) {
    // desired code
    /** here this refer to the current res instance and you can even access req for this res: **/
    console.log(this.req);
    render.apply(this, arguments);
};

недавно я обнаружил, что мне нужно сделать то же самое, чтобы предоставить идентификатор свойства Google Analytics и домен cookie для каждого из моих шаблонов.

здесь есть несколько отличных решений.

я решил пойти с чем-то очень близким к решению, предложенному Lex, но столкнулся с проблемами, когда звонки в res.render () еще не включил существующие параметры. Например, следующий код вызывает исключение при вызове extend (), потому что параметры не были определены:

return res.render('admin/refreshes');

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

app.use(function(req, res, next) {
  var _render = res.render;
  res.render = function(view, options, callback) {
    if (typeof options === 'function') {
      callback = options;
      options = {};
    } else if (!options) {
      options = {};
    }
    extend(options, {
      gaPropertyID: config.googleAnalytics.propertyID,
      gaCookieDomain: config.googleAnalytics.cookieDomain
    });
    _render.call(this, view, options, callback);
  }
  next();
});

edit: оказывается, что, хотя все это может быть удобно, когда мне нужно запустить какой-то код, есть чрезвычайно простой способ выполнить то, что я пытался сделать. Я снова посмотрел на источник и документы для Express, и оказывается, что приложение.locals используются для рендеринга каждого шаблона. Поэтому в моем случае я в конечном итоге заменил весь код промежуточного ПО выше следующими назначениями:

app.locals.gaPropertyID = config.googleAnalytics.propertyID;
app.locals.gaCookieDomain = config.googleAnalytics.cookieDomain;