如何使用express和handlebar或其他模板引擎在node.js中呈现rest API调用?

用例

使用Node.js,Express和像Handlebars这样的模板引擎来查询其他API,如Wordpress和CouchDB并呈现结果。

我已经走了那么远

var https = require('https'); var express = require('express'); var handlebars = require('express-handlebars') .create({ defaultLayout:'main' }); var app = express(); app.engine('handlebars', handlebars.engine); app.set('view engine', 'handlebars'); app.set('port', process.env.PORT || 3000); app.set('ip', process.env.IP); var options = { hostname: 'public-api.wordpress.com', path: '/rest/v1.1/sites/somesite.wordpress.com/posts/16', method: 'GET' }; app.get('/test', function(req, res) { https.request(options, function(restRes) { console.log('STATUS: ' + restRes.statusCode); res.render('home', { "title": "Test" }); // This code works. restRes.on('data', function (jsonResult) { // res.render('home', { "title": "Test" }); This code (after removing the line above) does not work. console.log('BODY: ' + jsonResult); }); }).end(); }); app.listen(app.get('port'), app.get('ip'), function(){ console.log( 'Express started on http://' + app.get('ip') + ": " + app.get('port') + '; press Ctrl-C to terminate.' ); }); 

这个代码工作,jsonResult在控制台显示正确。 移动行res.render('home', { "title": "Test" });restRes.on('data', function (jsonResult) callback)里面会引发一个错误。

 Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11) at ServerResponse.header (/home/ubuntu/workspace/node_modules/express/lib/response.js:718:10) at ServerResponse.send (/home/ubuntu/workspace/node_modules/express/lib/response.js:163:12) at res.render.done (/home/ubuntu/workspace/node_modules/express/lib/response.js:957:10) at Immediate._onImmediate (/home/ubuntu/workspace/node_modules/express-handlebars/lib/utils.js:26:13) at processImmediate [as _immediateCallback] (timers.js:374:17) 

我是否监督一个明显的错误? 如何以正确的方式做到这一点?

错误是不言自明的,那就是当响应已经发送时你不能设置标题。 错误可能由于以下原因而发生

原因1

以下失败,因为您尝试多次发送响应。

 //the following lines send the response res.render('home', { "title": "Test" }); // This code works. restRes.on('data', function (jsonResult) { //you have already send the response above, hence the error res.render('home', { "title": "Test" }); This code (after removing the line above) does not work. console.log('BODY: ' + jsonResult); }); 

原因2

这会失败并显示错误,因为.on('data')被多次调用(取决于响应的大小),这是因为数据是以块的forms返回的,因此您正试图res.render多次。

 restRes.on('data', function (jsonResult) { res.render('home', { "title": "Test" }); console.log('BODY: ' + jsonResult); }); 

可能的scheme

您需要使用.on('data')来接收块,然后在这里构build完整的响应,然后使用.on('end')以完整的响应执行res.render 。 如下所示:

 var body = ''; //use the chunks to build the whole response into body variable restRes.on('data', function (chunk) { body += chunk; }); //this is called when the request is finished and response is returned //hence, use the constructed body string to parse it to json and return restRes.on('end', function () { console.log('whole response > ' + body); var jsonObject = JSON.parse(body); res.render('home', {data:jsonObject}); //in your view use the data that is json object. }); 

另一种可能的解决scheme不是连接返回给.on('data')的块,你可以将它们推入一个数组,然后在.on('end')中join数组元素,这些元素将构造响应体,然后parsing它到JSON,然后返回它。 示例如下:

 var body = []; restRes.on('data', function(chunk) { body.push(chunk); }); restRes.on('end', function() { //joined the chunks var result = JSON.parse(data.join('')) res.render('home', {data: result}); });