2012-02-14 13 views
21

Connect/Express.js ile bir Node.js uygulaması yapıyorum ve orijinal render işlevine iletmeden önce bazı kodları çalıştırmak için res.render (view, option) işlevini engellemek istiyorum.Node.js/Express.js - Res.render işlevi nasıl geçersiz kılınır/durdurulur?

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' }); 
}); 

Gönüllü bir örnek gibi görünüyor, ancak yapıyorum genel bir çerçeveye sığmıyor.

JavaScript'teki OOP ve Prototypal kalıtım hakkındaki bilgim biraz zayıf. Böyle bir şeyi nasıl yapardım?


Güncelleme: Aşağıdaki ile geldi bazı denemeler sonra:

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' }); 
}); 

İşe görünüyor. Her istek için yeni bir yanıt sarmalayıcı nesnesi oluşturduğumdan en iyi çözüm olup olmadığından emin değil misiniz?

+1

normalde böyle yaparız o. Bunu, yönlendiriciden önce kullanılan bir ara katmana koyarsanız, tek bir yerde ayarlayabilirsiniz. –

+0

Ara katman yazılımı kullanmayı düşündüm. Tüm uygulama için yanıt davranışını geçersiz kılmak isteyip istemediğimi, yalnızca çerçevemde yönlendirilen istekler için emin değilim. –

cevap

22

Eski soruyu, ama kendimi soran bulundu aynı şey. Res intercept nasıl? Şimdi ekspres 4.0x bir şey kullanma.

Ara yazılımları kullanabilir/yazabilirsiniz. İlk başta konsept benim için biraz ürkütücüdü, ama biraz okuduktan sonra biraz daha anlamlı geldi. Ve sadece bunu okuyan herkes için bir bağlam için, res.render'ı geçersiz kılmaya yönelik motivasyon küresel görüş değişkenleri sağlamaktı. Tüm şablonlarda, her res nesnesine yazmam gerekmeden session olmasını istiyorum.

Temel katman yazılımı biçimi.

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

Bir sonraki param ve işlev çağrısı yürütme için çok önemlidir. next, çoklu ara katman yazılımlarının engellemeden kendi işini yapmasına izin vermek için geri arama işlevidir. Bu daha sonra kullanılabilir explanation read here

daha iyi üzerinde lojik

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(); 
}); 

hale geçersiz kılmak için ben ekspres 3.0.6 kullanarak, bu kodu test ettik. Sorun olmadan 4.x ile çalışmalıdır. Ayrıca

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

Bu, her istekte işlevi devre dışı bırakıyor mu? Prototipi geçersiz kılmak daha mantıklı olur mu? – jocull

+0

Bu, her istekte geçersiz kılar. Özellik gölgesiyle prototipi geçersiz kılar. İsterseniz prototipi geçersiz kılabilir, ancak genellikle prototip zincirinde derin olmayan ana nesne üzerinde özellikler istersiniz. Özellik arama süresi bu şekilde daha hızlıdır. – Lex

+1

Bu cevabı ilk başta almadım, ama kendimden çok şey öğrendikten sonra şimdi anladım. Lex'in bir varyasyonunu https://github.com/mettamage/renderExtMiddleware - '_.extend (args) 'kullanmadım. Kodum normal bir görünüm oluşturur * İstemci bir tarayıcı olmadığında * hariç *, o zaman json döndürür. –

7

response nesnesinin bir prototipi yoktur. ServerResponse.prototype kesmek daha iyi olabilir Ancak

var wrapRender = function(req, res, next) { 
    var _render = res.render; 
    res.render = function(view, options, callback) { 
    _render.call(res, "testViews/" + view, options, callback); 
    }; 
}; 

: Bu (a ortakatmanlarına koyma Ryan'ın fikrini alarak) çalışması gerekir

var express = require("express") 
    , http = require("http") 
    , response = http.ServerResponse.prototype 
    , _render = response.render; 

response.render = function(view, options, callback) { 
    _render.call(this, "testViews/" + view, options, callback); 
}; 
+0

Bunun için teşekkürler. Bu, düzen/ana görünümün nasıl göründüğünü kırsa da, 'testViews/layout.ejs' dosyasını aramaya çalışır. Kaynağa baktım ve yanıt nesnesinde bir _render yönteminin zaten tanımlandığını gördüm, bu sorunlara neden olabilir mi? –

+0

Evet, doğru - tüm görünümlere "testViews /" ifadesini ekleyecek. ServerResponse._render ile hiçbir ilgisi yoktur. Neyi başarmaya çalışıyorsun? –

+0

ServerRespone.prototype kesmek için çalıştı ve başarısız oldu. Sanırım bu, node 0.6/express 2'de çalıştı? Bu işi node 0.8'de nasıl yapabileceğiniz hakkında bir fikriniz var mı? –

6

Bu katman her isteğe ve her biri için idam çünkü bunların her örneği için bir yanıt veya istek yöntemini geçersiz kılmak için bir ara katman kullanmak iyi bir fikir değil belirli URL'leri tarak geçersiz kılabilir yeni bir işlev yarattığınız için cpu ve bellek kullanımı çağrılır.

Bildiğiniz gibi javascript Prototip tabanlı bir dildir ve her nesnenin yanıt ve istek nesneleri gibi bir prototipi vardır. Koduna bakarak (ekspres 4.13.4) kendi prototip bulabilirsiniz: bunu çok daha iyi bir zamanlar bitti gibi en prototip bunu geçersiz kılmak için var bir tepkinin her örneği için bir yöntem geçersiz kılmak istediğinizde Yani

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

her durumda kullanılabilir yanıtın:

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); 
}; 
+1

Bu yorumun neden kabul edilmediğini bilmiyorum! mutlak doğru cevap! –

3

Geçenlerde kendimi şablonları her birine bir yapılandırma özgü Google Analytics mülk kimliği ve çerez alanını sağlamak üzere, aynı şeyi yapmak gerek bulundu.

Burada bir çok harika çözüm var.

Lex tarafından önerilen çözüme çok yakın bir şeyle gitmeyi tercih ettim, ancak res.render() öğesine yapılan çağrıların halihazırda mevcut seçenekleri içermediği sorunlara yol açtım. seçenekler tanımsız çünkü Örneğin, aşağıdaki kod,) (genişletmek için çağrıda istisna neden oldu:

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

ekledim callback'inde dahil mümkündür argümanlar çeşitli kombinasyonları göz önünde bulundurulmakta olan aşağıdaki . Benzer bir yaklaşım, başkaları tarafından önerilen çözümlerle kullanılabilir.

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(); 
}); 

düzenleme: Aslında bazı kodlar çalıştırmak gerektiğinde bu tüm kullanışlı olabilirken, yapmaya çalıştığım şey başarmak için müthiş basit bir yolu var olduğunu ortaya çıktı. Express'in kaynağına ve belgelerine tekrar baktım ve app.locals öğelerinin her bir şablonu oluşturmak için kullanıldığını görüyoruz. Yani benim durumumda, ben sonuçta aşağıdaki atamaları ile üzerindeki orta kodunun tüm değiştirilir:

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

İki gerçekten iyi puan. Yerliler mülkiyeti çoğu durumda uygun olurdu. Ve geri dönüşü tanımsız hale getirmek için herhangi bir seçenek geçilmezse ve tüm cehennem gevşer. – Lex