No se puede configurar el encabezado en KOA cuando se usa la devolución de llamada
Pregunta
Recientemente trabajé en un nuevo proyecto que utilizaba devoluciones de llamada de JavaScript.Y estaba usando koa estructura.Pero cuando llamé a esta ruta:
function * getCubes(next) {
var that = this;
_OLAPSchemaProvider.LoadCubesJSon(function(result) {
that.body = JSON.stringify(result.toString());
});
}
Recibo 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)
Solución
El problema es que tu llamada asíncrona LoadCubesJSon()
Tarda un poco en regresar pero Koa no se da cuenta y continúa con el flujo de control.Eso es básicamente lo que yield
es para.
Los objetos "rendibles" incluyen promesas, generadores y procesadores (entre otros).
Personalmente prefiero crear manualmente una promesa con el Biblioteca 'Q'.Pero puedes usar cualquier otra biblioteca de promesas o node-thunkify
para crear un golpe seco.
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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow