javascript - requests - node js http request
Node.js/Express.js-¿Cómo anular/interceptar la función res.render? (4)
El objeto de response
no tiene un prototipo. Esto debería funcionar (tomando la idea de Ryan de ponerlo en un middleware):
var wrapRender = function(req, res, next) {
var _render = res.render;
res.render = function(view, options, callback) {
_render.call(res, "testViews/" + view, options, callback);
};
};
Sin embargo, podría ser mejor piratear el ServerResponse.prototype:
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);
};
Estoy construyendo una aplicación Node.js con Connect / Express.js y quiero interceptar la función res.render (ver, opción) para ejecutar algún código antes de reenviarlo a la función de renderización original.
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'' });
});
Parece un ejemplo artificial, pero encaja en un marco general que estoy construyendo.
Mi conocimiento de OOP y herencia de Prototypal en JavaScript es un poco débil. ¿Cómo haría algo como esto?
Actualización: después de algunos experimentos, se me ocurrió lo siguiente:
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'' });
});
Parece funcionar. No estoy seguro de si es la mejor solución ya que estoy creando un nuevo objeto envoltorio de respuesta para cada solicitud, ¿sería un problema?
No es una buena idea usar un middleware para anular una respuesta o un método de solicitud para cada instancia de ellos porque el middleware se ejecuta para cada solicitud y cada vez que se llama utiliza la CPU y la memoria porque está creando un nueva función.
Como sabrá, javascript es un lenguaje basado en prototipos y cada objeto tiene un prototipo, como los objetos de respuesta y solicitud. Al mirar el código ( expresión 4.13.4 ) puede encontrar sus prototipos:
req => express.request
res => express.response
Por lo tanto, cuando desea anular un método para cada instancia de respuesta, es mucho mejor anularlo en su prototipo, ya que está disponible una vez que está disponible en cada instancia de respuesta:
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);
};
Recientemente me di cuenta de que necesitaba hacer lo mismo para proporcionar un ID de propiedad e identificación de Google Analytics específico para cada una de mis plantillas.
Hay una serie de excelentes soluciones aquí.
Elegí ir con algo muy parecido a la solución propuesta por Lex, pero me encontré con problemas donde las llamadas a res.render () aún no incluían las opciones existentes. Por ejemplo, el siguiente código causaba una excepción en la llamada a extender (), porque las opciones no estaban definidas:
return res.render(''admin/refreshes'');
Agregué lo siguiente, que explica las diversas combinaciones de argumentos que son posibles, incluida la devolución de llamada. Un enfoque similar se puede usar con las soluciones propuestas por otros.
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();
});
editar: Resulta que si bien todo esto puede ser útil cuando necesito ejecutar algún código, hay una forma tremendamente más simple de lograr lo que estaba tratando de hacer. Miré de nuevo a la fuente y documentos para Express, y resulta que los app.locals se utilizan para representar cada plantilla. Entonces, en mi caso, finalmente reemplacé todo el código de middleware anterior con las siguientes asignaciones:
app.locals.gaPropertyID = config.googleAnalytics.propertyID;
app.locals.gaCookieDomain = config.googleAnalytics.cookieDomain;
Una vieja pregunta, pero me encontré preguntando lo mismo. Cómo interceptar res render? Usando express 4.0x algo ahora.
Puedes usar / escribir middleware. El concepto fue un poco abrumador para mí al principio, pero después de leerlo tuvo un poco más de sentido. Y solo para un contexto para cualquier persona que lea esto, la motivación para reemplazar a res.render fue proporcionar variables de vista global. Quiero que la session
esté disponible en todas mis plantillas sin que tenga que escribirla en cada objeto res.
El formato básico de middleware es.
app.use( function( req, res, next ) {
//....
next();
} );
El próximo param y llamada de función son cruciales para la ejecución. next
es la función de devolución de llamada, para permitir que varios middleware hagan lo suyo sin bloquear. Para una mejor explicación, lee aquí
Esto puede usarse para anular la lógica de renderizado
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();
} );
He probado este código, usando express 3.0.6. Debería funcionar con 4.x sin problema. También puede anular combinaciones de URL específicas con
app.use( ''/myspcificurl'', function( req, res, next ) {...} );