Express: Can't set headers after they are sent - node.js

Following is my server file. I am making 2 calls, one post and one get. It works fine at times. But gives an error of : Can't set headers after they are sent. Does this have anything to do with my client side code?
server.js
var express = require('express')
var mongoose = require('mongoose')
var path = require('path')
var bodyParser = require("body-parser")
var cors = require("cors")
var app = express()
var port = process.env.PORT || 3000
var Url = require("./data/url-schema");
//Express request pipeline
app.use(express.static(path.join(__dirname,"../client")))
app.use(bodyParser.json())
app.use(cors());
/*
Your server must be ready to handle real URLs. When the app first loads at / it will probably work, but as the user navigates around and then hits refresh at /dashboard your web server will get a request to /dashboard. You will need it to handle that URL and include your JavaScript application in the response.
*/
app.get('*', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
app.get('/:code', function(req, res) {
console.log("reg", req.params.code)
Url.findOne({code:req.params.code}, function(err, data){
console.log("data", data)
if(data)
res.redirect(302, data.longUrl)
else
res.end()
})
})
app.post('/addUrl', function (req, res, next) {
console.log("on create");
Url.findOne({longUrl:req.body.longUrl}, function(err, data) {
if (err)
res.send(err);
else if(data) {
console.log("already exists",data)
res.send("http://localhost:3000/"+data.code);
} else {
var url = new Url({
code : Utility.randomString(6,"abcdefghijklm"),
longUrl : req.body.longUrl
});
console.log("in last else data created",url)
url.save(function (err, data) {
console.log(data)
if (err)
res.send(err);
else
res.send("http://localhost:3000/"+data.code);
});
}
});
})
app.listen(port, function () {
console.log('Example app listening on port 3000!')
});
// Connect to our mongo database
mongoose.connect('mongodb://localhost/shortUrl');
I get the Following error
error
_http_outgoing.js:335
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:335:11)
at ServerResponse.header (/opt/lampp/htdocs/url-shortener/node_modules/express/lib/response.js:718:10)
at ServerResponse.location (/opt/lampp/htdocs/url-shortener/node_modules/express/lib/response.js:835:8)
at ServerResponse.redirect (/opt/lampp/htdocs/url-shortener/node_modules/express/lib/response.js:874:8)
at Query.<anonymous> (/opt/lampp/htdocs/url-shortener/server/server.js:30:8)
at /opt/lampp/htdocs/url-shortener/node_modules/mongoose/node_modules/kareem/index.js:177:19
at /opt/lampp/htdocs/url-shortener/node_modules/mongoose/node_modules/kareem/index.js:109:16
at process._tickCallback (node.js:355:11)

From the execution order, in * route handler, the body is being assigned to the response and then in /:code, the response code 302 is being added, where Location header is also added, hence the error. Any header must be added before the body to the response.
To solve this problem, simply change the order of the two GET statements.

Finally found the solution:
var express = require('express')
var mongoose = require('mongoose')
var path = require('path')
var bodyParser = require("body-parser")
var app = express()
var port = process.env.PORT || 3000
var Url = require("./data/url-schema")
var Utility = require("./utility")
//Express request pipeline
app.use(express.static(path.join(__dirname,"../client")))
app.use(bodyParser.json())
/*
Your server must be ready to handle real URLs. When the app first loads at / it will probably work, but as the user navigates around and then hits refresh at /dashboard your web server will get a request to /dashboard. You will need it to handle that URL and include your JavaScript application in the response.
*/
app.get('/dashboard', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
app.get('/about', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
app.get('/:code', function(req, res) {
Url.findOne({code:req.params.code}, function(err, data){
if(data){
res.redirect(302, data.longUrl)
}
})
})
app.post('/addUrl', function (req, res, next) {
Url.findOne({longUrl:req.body.longUrl}, function(err, data) {
if (err){
res.send(err)
}
else if(data) {
res.send("http://localhost:3000/"+data.code);
} else {
var newCode = getCode()
checkCode(newCode)
.then(function(data){
var url = new Url({
code : data,
longUrl : req.body.longUrl
});
url.save(function (err, data) {
if (err)
res.send(err);
else
res.send("http://localhost:3000/"+data.code);
});
})
}
});
})
app.listen(port, function () {
console.log('Example app listening on port 3000!')
});
// Connect to our mongo database
mongoose.connect('mongodb://localhost/shortUrl');
//Generate a random code
function getCode() {
return Utility.randomString(6,"abcdefghijklmnopqrstuvwxyz")
}
//Check if the code is unique
function checkCode(code) {
return new Promise(function (resolve, reject){
Url.findOne({code:code}, function(err, data) {
if(err === null){
resolve(code)
}else if(data){
saveUrlCode(getCode())
}
})
})
}
My earlier route which was :
app.get('*', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
The get route was getting executed twice on account of the above call and the
app.get(":/code") call.
So I had to handle the routes properly which I have done by handling the dashboard and about routes separately instead of using the "*" route.

Related

ERR_HTTP_HEADERS_SENT node js socket connection

I am building an API that uses socket connection to interact with a server backend built in C#. This is what I have so far
const request = require('request');
const express = require('express');
const app = express();
var server = require('http').createServer(app);
var cors = require("cors");
app.use(cors());
const net = require('net');
const client = new net.Socket();
const stringToJson=require('./stringToJson')
const port = process.env.PORT;
const host = process.env.HOST;
client.keepAlive=true
client.on('close', function() {
console.log('Connection closed');
});
app.get('/getScores',function (req,res) {
let dataSend=''
client.on('data', function (data) {
console.log('Server Says : ' + data);
if(data!='ANALYSIS-ERROR'){
dataSend=stringToJson.stringToJson(data)
}
else{
dataSend=stringToJson.stringToJson('0:0.0:0.0:0.0:0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0')
}
client.destroy()
return res.send(dataSend)
});
client.connect(port, host, function () {
client.write(`GENERAL-ANALYSIS|${req.query.id}|${req.query.website}|`)
return
});
return
})
app.get('/getPlace',function (req,res) {
console.log(req.query)
request(
{ url: `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${req.query.name}+in+${req.query.city}&key=${process.env.API_KEY}` },
(error, response, body) => {
if (error || response.statusCode !== 200) {
return res.status(500).json({ type: 'error', message: error.message });
}
return res.json(JSON.parse(body));
}
)
})
//TODO ADD 404 500 PAGES
app.use((req, res, next) => {
res.status(404).send("Sorry can't find that!");
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
server.listen(9000, () => {
console.log(`App running at http://localhost:9000`);
});
Basically it creates a connection with the server and listens for some data to be sent back. Then processes the string and sends it to the React frontend. The api calls are made by the frontend using axios
It works but if you refresh the page it throws this error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How do I fix this?
Try setting the headers as found in the documentation request.setHeader(name, value)
request.setHeader('Content-Type', 'application/json');

How to fix 'headers already sent' error in node

So I'm trying to create a node app that calls an ldap serve and to authenticate users. In the code below, the app successfully connects to the server and processes the request. But when I try to send a response back, I get this error:
throw new ERR_HTTP_HEADERS_SENT('set');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I'm not really sure why this is occurring. I'm pretty new to node, express, and ldap
// ldapjs required for ldap connection
const ldap = require('ldapjs');
//express required for exposing endpoints
const express = require('express');
const app = express();
const assert = require('assert');
var client = ldap.createClient({
url: 'ldap://someserve.com'
});
//Search filter for users in the directory
var opts = {
filter: '(&(objectCategory=person)(objectClass=user))',
scope: 'sub',
};
//General Ldap serch user
var UserName = '123.test.com';
var Pass = '123longpass'
//Base URL
app.get('/', (req,res) => {
res.send('hello from node')
});
//Get all ldap users
app.get('/api/ldapUsers', (req, res) =>
{
client.bind(UserName, Pass, function (err)
{
client.search('DC=sdf,DC=sdfa,DC=gdfgd', opts, function (err, search)
{
search.on('searchEntry', function (entry)
{
res.setHeader('Content-Type', 'application/json');
var users = entry.object;
console.log(users);
res.json(users);
res.end();
});
});
});
// client.unbind( err => {
// assert.ifError(err);
// });
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
searchEntry event is called once for each found item which means you are calling res.json multiple times.
Try this:
app.get('/api/ldapUsers', (req, res) =>
{
client.bind(UserName, Pass, function (err)
{
client.search('DC=sdf,DC=sdfa,DC=gdfgd', opts, function (err, search)
{
var users = [];
search.on('searchEntry', function (entry) {
users.push(entry.object);
});
search.on('end', function (entry) {
res.setHeader('Content-Type', 'application/json');
console.log(users);
res.json(users);
res.end();
});
});
});
});

Node: Is it possible that http server on request return the content from a request module?

What I want to do is to make a request using the "request" module when server receives a request, and return the content of that "request" back to the client. Is it possible?
const http = require("http");
const request = require("request");
const URL = "???";
const server = http.createServer();
server.on('request', (req, res) => {
// called once for every HTTP request
out_res = res;
make_request((err, res, body) => {
out_res.writeHead(200, {res});
out_res.write(body);
out_res.end();
});
});
function make_request(callback) {
request(URL, (err, res, body) => {
callback(err, res, body);
});
}
module.exports = () => {
server.listen(8080);
console.log('server start');
};
I got an error: ERR_STREAM_WRITE_AFTER_END, I've been a long time without node.js, but my friend asked me about some code and I just rewrite as above.
Ofcourse you can do that
server.on('request', (req, res) => {
request({uri: URL}).pipe(res);
});
Just pipe the response of API call to your router response object.
Here is how I would advise you to write your server code
var server = http.createServer(function(req,res){
if(req.url === '/' || req.url === '/index'){
request({uri: URL}).pipe(res);
}
.... //other conditions
});
server.listen(3000,'127.0.0.1')
Moreover, you can/should consider using express, it's really cool and easy to use to define routes etc

formidable parse callback not be called and no error

I have problem when I use formidable parse function. In my project, I use httpsys (not build-in http module) to create server (for port sharing), and then I send a post request with multipart form data(including string and zip file). Then I want to use formidable to parse request body. But parse function callback does not be called. There is no error. I do not use Express application, but I use Express Router to route my requests. I already use error handler to catch error, but it never be called (form.on('error', function(err) { console.log(err); });). Anyone has same problem? Please help me out, thanks in advance.
// main.js
var router = express.Router();
router.use(function (req, res, next) {
for (var i in req.headers) {
req.headers[i] = querystring.unescape(req.headers[i]);
req.headers[i] = req.headers[i].replace(/\+/g, "");
}
next();
});
//router.use(bodyParser());
router.post('/TestServer/' + 'TestRequest', function(req, res) {
testRequestHandler.execute(req, res);
});
var server = require('httpsys').http().createServer(router);
var port = '80'; // or other port
var listeningPort = 'http://localhost:' + port + '/TestServer/';
server.listen(listeningPort );
// In testRequestHandler
var execute = function(req, res) {
var form = new Formidable.IncomingForm();
form.uploadDir = uploadDir.getPath();
form.encoding = Constants.ENCODING_UTF8;
form.on('file', function(name, file) {console.log('file='+file);});
form.on('error', function(err) { console.log(err); }); // never be called
form.on('aborted', function() { console.log('Aborted'); });
form.parse(req, function(err, fields, files) {
//todo test code
console.log( "parse finished" );
});
}

no req.params sent in the requests

In a practice example, i'm trying to create a restfull API, very simple. The plain GET and POST methods works well, but the GET, PUT and DELETE method pointing to /api/bears/:bear_id just stay there, waiting...
// CONFIGURACION INICIAL //
// ===================== //
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var db = mongoose.connection;
// CONFIGURANDO APP //
// ================ //
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
mongoose.connect('mongodb://localhost:27017/bears');
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function cb () {
console.log('conexion establecida');
})
var Bear = require('./models/bear_model.js');
var port = process.env.PORT || 8080; // seteo del puerto
var router = express.Router(); // instancia del ruteador
Above, the simple config, below, the snippet that is causing me problems:
router.use(function (req, res, next) { // simple logger
if (req.method === 'GET')
console.log('executing query on id %s', JSON.stringify(req.params));
else if (req.method === 'PUT')
console.log('executing query on id %s', JSON.stringify(req.params));
else
console.log('executing query on id %s', JSON.stringify(req.params));
});
router.route('/bears/:bear_id')
.get(function (req, res) {
Bear.findById(req.params.bear_id, function (err, bear) {
if (err)
res.send(err);
res.json(bear);
});
}) // end GET /bears/:bear_id
.put(function (req, res) {
Bear.findById(req.params.bear_id, function (err, bear) {
if (err)
res.send(err)
bear.name = req.body.name; // Update bear_id of Bear
bear.save(function (err) {
if (err)
res.send(err);
res.json({msg: 'Bear actualizado!'});
});
});
}) // end PUT /bears/:bear_id
.delete(function (req, res) {
Bear.remove({
_id: req.params.bear_id
}, function (err, bear) {
if (err)
res.send(err);
res.json({ msg: 'Bear eliminado' });
});
}); // end DELETE /bears/:id && router /bears/:id
app.use('/api', router); // la api usarĂ¡ como base el prefijo /api
Executing one route with a param log me: executing query on {}, so, the req.params.bear_id simply is not captured, and if i change req.params by req.params.bears_id, obviously i get an undefined log, so i read de docs and think i'm doing generally well the process but don't catch the issue.
You are not calling next() in your logger, so you're never getting to your router, which results in no response.
router.use(function (req, res, next) { // simple logger
if (req.method === 'GET')
console.log('executing query on id %s', JSON.stringify(req.params));
else if (req.method === 'PUT')
console.log('executing query on id %s', JSON.stringify(req.params));
else
console.log('executing query on id %s', JSON.stringify(req.params));
next();
});
Now the reason you are not seeing params in your logger is because params are only visible if the route definition has params. Your logger middleware doesn't define a specific route, therefore there are no params. A solution to this would be to use Router.param
router.param('bear_id', function(req, res, next, bear_id) {
if (req.method === 'GET')
console.log('executing query on id ' + bear_id);
else if (req.method === 'PUT')
console.log('executing query on id ' + bear_id);
else
console.log('executing query on id ' + bear_id);
next();
});
More simply:
router.param('bear_id', function(req, res, next, bear_id) {
console.log(req.method + ' with id ' + bear_id);
next();
});
This works this way by design, you can find more information on github:
https://github.com/strongloop/express/issues/2088

Resources