node.js - ctx - No se puede establecer el encabezado en KOA cuando se usa la devolución de llamada
koa vs express (1)
Recientemente trabajé en un nuevo proyecto que usa devoluciones de llamada de javascript. Y estaba usando el framework koa . Pero cuando llamé a esta ruta:
function * getCubes(next) {
var that = this;
_OLAPSchemaProvider.LoadCubesJSon(function(result) {
that.body = JSON.stringify(result.toString());
});
}
Me sale este error:
_http_outgoing.js:331
throw new Error(''Can/'t set headers after they are sent.'');
^
Error: Can''t set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11)
at Object.module.exports.set (G:/NAP/node_modules/koa/lib/response.js:396:16)
at Object.length (G:/NAP/node_modules/koa/lib/response.js:178:10)
at Object.body (G:/NAP/node_modules/koa/lib/response.js:149:19)
at Object.body (G:/NAP/node_modules/koa/node_modules/delegates/index.js:91:31)
at G:/NAP/Server/OlapServer/index.js:42:19
at G:/NAP/Server/OlapServer/OLAPSchemaProvider.js:1599:9
at _LoadCubes.xmlaRequest.success (G:/NAP/Server/OlapServer/OLAPSchemaProvider.js:1107:13)
at Object.Xmla._requestSuccess (G:/NAP/node_modules/xmla4js/src/Xmla.js:2110:50)
at Object.ajaxOptions.complete (G:/NAP/node_modules/xmla4js/src/Xmla.js:2021:34)
El problema es que su llamada asíncrona LoadCubesJSon()
demora un tiempo en regresar, pero Koa no lo sabe y continúa con el flujo de control. Para eso es básicamente el yield
.
Los objetos "fiables" incluyen promesas, generadores y thunks (entre otros).
Personalmente prefiero crear una promesa manualmente con la biblioteca ''Q'' . Pero puedes usar cualquier otra biblioteca de promesas o node-thunkify
para crear un thunk.
Aquí hay un ejemplo breve pero funcional con Q
:
var koa = require(''koa'');
var q = require(''q'');
var app = koa();
app.use(function *() {
// We manually create a promise first.
var deferred = q.defer();
// setTimeout simulates an async call.
// Inside the traditional callback we would then resolve the promise with the callback return value.
setTimeout(function () {
deferred.resolve(''Hello World'');
}, 1000);
// Meanwhile, we return the promise to yield for.
this.body = yield deferred.promise;
});
app.listen(3000);
Entonces su código se vería de la siguiente manera:
function * getCubes(next) {
var deferred = q.defer();
_OLAPSchemaProvider.LoadCubesJSon(function (result) {
var output = JSON.stringify(result.toString());
deferred.resolve(output);
});
this.body = yield deferred.promise;
}