我正在开发一个小节点& express.js应用程序。
我在app.get('/lastName/:lastName',(req,res) =>{...});
找到了
如果我使用:
res.render('employeeList',{data:employees.lookupByLastName(paramsLastName)});
它始终与res.format({...});
冲突
它给了我一个错误:
throw new Error('Can\'t set headers after they are sent.');
当我单独使用它们时,在http://localhost:3000/lastName/Smith我可以得到正确的视图。如果我只使用res.format({...});
,我也可以通过以下方式获得正确的api反馈:
curl -X GET -H "Accept:application/xml" "http://localhost:3000/lastName/Smith"
但是,我不能同时使用它们,这与分配要求相冲突。 有人能给我一些线索吗?非常感谢!请参阅以下代码:
'use strict';
const express = require('express');
const _= require('underscore');
const handlebars = require('express-handlebars');
const employees = require('./employeeModule.js');
const bodyParser = require('body-parser');
const app = express();
app.engine('handlebars',
handlebars({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
// GET request to the homepage
app.get('/', (req, res) => {
res.render('home');
});
app.get('/addEmployee',(req,res) => {
res.render('newEmployee');
});
//..........................Problem here.........................
app.get('/id/:id',(req,res)=>{
let paramsId = parseInt(req.params.id);
//res.render('employeeList',{data:employees.lookupById(paramsId)});
//res.send(employees.lookupById(paramsId));
res.format({
'application/json': () => {
res.json(employees.lookupById(paramsId));
},
'application/xml': () => {
let employeeXml =
'<?xml version="1.0"?>\n<employees>\n' +
employees.lookupById(paramsId).map((e)=>{
return ' <employee id="' + e.id + '">' +
'<firstName>' + e.firstName + '</firstName>'+ '<lastName>' + e.lastName + '</lastName>' + '</employee>';
}).join('\n') + '\n</employees>\n';
res.type('application/xml');
res.send(employeeXml);
},
'text/html': () => {
let employeeHtml = '<ul>\n' +
employees.lookupById(paramsId).map((e)=>{
return ' <li>' + e.id + ' - ' +
e.firstName + ' - ' + e.lastName+'</li>';
}).join('\n') + '\n</ul>\n';
res.type('text/html');
res.send(employeeHtml);
},
'text/plain': () => {
let employeeText =
employees.lookupById(paramsId).map((e)=>{
return e.id + ': ' + e.firstName + e.lastName;
}).join('\n') + '\n';
res.type('text/plain');
res.send(employeeText);
},
'default': () => {
res.status(404);
res.send("<b>404 - Not Found</b>");
}
});
});
//..........................Problem here.........................
app.get('/lastName/:lastName',(req,res) =>{
let paramsLastName = req.params.lastName;
res.render('employeeList',{data:employees.lookupByLastName(paramsLastName)});
res.format({
'application/json': () => {
res.json(employees.lookupByLastName(paramsLastName));
},
'application/xml': () => {
let employeeXml =
'<?xml version="1.0"?>\n<employees>\n' +
employees.lookupByLastName(paramsLastName).map((e)=>{
return ' <employee id="' + e.id + '">' +
'<firstName>' + e.firstName + '</firstName>'+ '<lastName>' + e.lastName + '</lastName>' + '</employee>';
}).join('\n') + '\n</employees>\n';
res.type('application/xml');
res.send(employeeXml);
},
'text/html': () => {
let employeeHtml = '<ul>\n' +
employees.lookupByLastName(paramsLastName).map((e)=>{
return ' <li>' + e.id + ' - ' +
e.firstName + ' - ' + e.lastName+'</li>';
}).join('\n') + '\n</ul>\n';
res.type('text/html');
res.send(employeeHtml);
},
'text/plain': () => {
let employeeText =
employees.lookupByLastName(paramsLastName).map((e)=>{
return e.id + ': ' + e.firstName + e.lastName;
}).join('\n') + '\n';
res.type('text/plain');
res.send(employeeText);
},
'default': () => {
res.status(404);
res.send("<b>404 - Not Found</b>");
}
});
});
app.post('/data',function (req,res) {
let bodyData = req.body;
let bodyDataFirstName = bodyData.firstName;
let bodyDataLastName = bodyData.lastName;
employees.addEmployee(bodyDataFirstName,bodyDataLastName);
res.redirect('/lastName/'+bodyDataLastName);
})
app.get('/api/employees',(req,res) =>{
res.format({
'application/json': () => {
res.json(employees.getAllEmployee());
},
'application/xml': () => {
let employeeXml =
'<?xml version="1.0"?>\n<employees>\n' +
employees.getAllEmployee().map((e)=>{
return ' <employee id="' + e.id + '">' +
e.firstName + e.lastName + '</employee>';
}).join('\n') + '\n</employees>\n';
res.type('application/xml');
res.send(employeeXml);
},
'text/html': () => {
let employeeHtml = '<ul>\n' +
employees.getAllEmployee().map((e)=>{
return ' <li>' + e.id + ' - ' +
e.firstName + ' - ' + e.lastName+'</li>';
}).join('\n') + '\n</ul>\n';
res.type('text/html');
res.send(employeeHtml);
},
'text/plain': () => {
let employeeText =
employees.getAllEmployee().map((e)=>{
return e.id + ': ' + e.firstName + e.lastName;
}).join('\n') + '\n';
res.type('text/plain');
res.send(employeeText);
},
'default': () => {
res.status(404);
res.send("<b>404 - Not Found</b>");
}
});
});
app.use((req, res) => {
res.status(404);
res.render('404');
});
app.listen(3000, () => {
console.log('http://localhost:3000');
});
/*
curl -X GET "http://localhost:3000/api/employees"
curl -X GET -H "Accept:application/json" "http://localhost:3000/api/employees"
curl -X GET -H "Accept:application/xml" "http://localhost:3000/api/employees"
curl -X GET -H "Accept:text/html" "http://localhost:3000/api/employees"
curl -X GET -H "Accept:text/plain" "http://localhost:3000/api/employees"
*/
/*
curl -X GET "http://localhost:3000/api/employees"
curl -X GET -H "Accept:application/json" "http://localhost:3000/lastName/Smith"
curl -X GET -H "Accept:application/xml" "http://localhost:3000/lastName/Smith"
curl -X GET -H "Accept:application/json" "http://localhost:3000/id/2"
curl -X GET -H "Accept:application/xml" "http://localhost:3000/id/2"
*/
答案 0 :(得分:0)
您正在向同一请求发送两次回复。
当您的代码尝试向同一请求发送两个响应时,会导致您收到错误消息。因此,您必须删除代码中可能发生的所有位置。
在GridLayout
处理程序中,您首先调用app.get('/lastName/:lastName', ...)
,然后尝试执行res.render()
。但是,您拨打res.send()
的方式,该通话已发送对该请求的回复,因此您无法再次拨打res.render()
或res.send()
,因为将尝试向同一请求发送另一个响应,这将触发您看到的错误消息。
如果您尝试仅渲染HTML,然后将该呈现的HTML用作稍后发送的响应的一部分,那么您需要使用其他形式的res.json()
来传递它回调,它会使用您稍后可以发送的HTML回拨您。
请参阅res.render()
的文档,了解如何使用回调选项获取HTML而不将其作为响应发送,以便以后在发送您要发送的响应时使用它。
一般方案是这样的:
res.render()
答案 1 :(得分:0)
您发送了两次回复。
您的res.render
呈现employeeList
,然后将其作为回复发送。之后,您尝试发送另一个响应,这是不允许的,并且与请求 - 响应周期不对应。
此外,您还在使用模板引擎呈现您的网页:
let paramsLastName = req.params.lastName;
res.render('employeeList',{data:employees.lookupByLastName(paramsLastName)});
然后你尝试在这里手动完成:
'text/html': () => {
let employeeHtml = '<ul>\n' +
employees.lookupById(paramsId).map((e)=>{
return ' <li>' + e.id + ' - ' +
e.firstName + ' - ' + e.lastName+'</li>';
}).join('\n') + '\n</ul>\n';
res.type('text/html');
res.send(employeeHtml);
}
您可以在res.format
下的'text/html'
内拨打res.render,
使用res.format
在app.render
块之外或之外 - 这会呈现html但不会将其作为回复发送。
app.render('index', {data:employees.lookupByLastName(paramsLastName)}, function(err, result) {
// result is the resulting html from rendering your data.
// save it to some variable to use later or do something with it here
});