Cant set headers after they are sent in Node.js - javascript

I am trying to understand how the following code works and the later doesnt.
var Todo = require('./models/database');
function getTodos(res){
Todo.find()
.sort('-created_at')
.exec(function(err, todos) {
if (err) return console.error(err);
// ISSUE HERE
res.json(todos, function(err){
if (err) console.log(err);
}); // return all todos in JSON format
});
};
module.exports = function(app) {
// api ---------------------------------------------------------------------
// get all todos
app.get('/api/todos', function(req, res) {
getTodos(res);
});
// update a todo
app.get('/api/todos/:todo_id/:replacedText', function(req, res) {
console.dir(req.params.todo_id);
console.dir(req.params.replacedText);
Todo.update({ _id : req.params.todo_id},
{$set: {text: req.params.replacedText}},
function(err, todo) {
if (err) res.send(err);
getTodos(res);
});
});
// application -------------------------------------------------------------
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
};
The above code works. But when i had the code under Todo.find() as:
// ISSUE HERE
res.json(todos); // return all todos in JSON format
This didnt work. I get the following error:
http http.js:689
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.js:689:11)
at ServerResponse.header (\node_modules\express\lib\response.js:595:10)
at ServerResponse.send (\node_modules\express\lib\response.js:143:12)
at ServerResponse.json (\node_modules\express\lib\response.js:229:15)
at Promise.<anonymous> (\app\routes.js:70:12)
at Promise.<anonymous> (\node_modules\mongoose\node_modules\mpromise\lib\promise.js:177:8)
at Promise.emit (events.js:95:17)
at Promise.emit (\node_modules\mongoose\node_modules\mpromise\lib\promise.js:84:38)
at Promise.fulfill (\node_modules\mongoose\node_modules\mpromise\lib\promise.js:97:20)
at Promise.resolve (\node_modules\mongoose\lib\promise.js:114:23)
Help me figure out, whats happening here.

Related

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 only on get request page

After building my project. I've noticed I am getting this error after building my application.
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
I am only getting this error message only on pages when I am using a get request.
My server code looks something like this
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
});
app.get('/api/global_rankings', function(request, response){
pool.connect((err, db, done) => {
if(err){
return response.status(400).send(err);
}
else{
db.query("some query", function(err, table){
done();
if(err){
return response.status(400).send(err);
}
else{
response.status(201).send({value: table.rows});
}
});
}
});
});
Ive noticed if i delete the first get request, my second get request works fine. However, I need the first get request or-else I get an GET error message when page is not refreshed.
source: https://tylermcginnis.com/react-router-cannot-get-url-refresh/
Is there any way I can fix this?
Thank you
You are getting a response, and the first character is < which I guarantee is an <html> tag because you are getting HTML back and trying to parse it as JSON.
The reason it works if you remove your first request is because * matches any request, including /api/global_rankings so when you have both methods it matches the * and returns an error page.
Switch the method order and see if it does not work like you want then:
app.get('/api/global_rankings', function(request, response){
pool.connect((err, db, done) => {
if(err){
return response.status(400).send(err);
}
else{
db.query("some query", function(err, table){
done();
if(err){
return response.status(400).send(err);
}
else{
response.status(201).send({value: table.rows});
}
});
}
});
});
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
});
You have to place the catch-all router /* at the end so it executes only if the route isn't /api/global_rankings:
app.get('/api/global_rankings', function(request, response) { ... }
app.get('/*', function(req, res) { ... });

Creating node server and setting error handlers in node js

I want to create a function that return a http.Server and
Serve the text of the file testText.txt in the body of the HTTP response
when a GET request is made to the '/' route.
Parse the request for a "paragraphs" parameter.
That parameter must be an integer and represent the number of
paragraph you want to receive starting from the beginning of the test text.
Return the appropriate content in the body of the response.
If any error happens, return a 500 error.
If the provided route is not known, return a 404 error.
here is what i have so far
function makeServer() {
return http.createServer(function(req, res){
if(req.url === '/'){
fs.readFile('testText.txt', function(err , para){
console.log("Data", para);
res.end();
});
console.log("The end");
}
}
I would expect to do something like this,
var express = require('express');
var app = express();
//Handle 404 here
app.use(function (req, res, next) {
res.status(404).send({
message: "Page Not Found"
})
});
Inject the GET request to your default route
app.get('/', (req, res) => {
// **modify your existing code here**
fs.readFile('testText.txt', (e, para) => {
if (e) {
res.status(500).send({
message: "Something went wrong"
})
}
res.send(para);
});
});
app.listen(5555);
As you have mentioned in your question use that err object inside the function such as below:
function makeServer() {
return http.createServer(function(req, res){
if(req.url === '/'){
fs.readFile('testText.txt', function(err , para){
if (err) {
res.status(500).send({
message: "Something went wrong"
})
// error handling
} else {
console.log("Data", para);
res.end();
}
});
console.log("The end");
}
}
Firstly, Welcome to the node world...
1) Work with file in res
Please refer this answer. It will help you.
2) Error code 500 if any error
res.status(500).json({success: 0, error 'Something went wrong'});
3) For handle 404 if route not matched
var createError = require('http-errors');
//Install via this command-> npm i http-errors --save
app.use(function (req, res, next) {
next(createError(404));
});

Node.js, Express: Cannot set headers after they are sent to the client [duplicate]

This question already has answers here:
Error: Can't set headers after they are sent to the client
(47 answers)
Closed 3 years ago.
First off, I read all other StackOverflow answers and GitHub Issues and none of them seem to have solved my problem. With the following code (some of it is deprecated, sorry for the dirty code):
var express = require('express');
var fs = require('fs');
var path = require('path');
var parser = require('body-parser');
//Initializing the Express Framework
const app = express();
const mongoose = require('mongoose');
const uuidv4 = require ('uuid/v4');
var jose = require('node-jose');
var secureRandom = require('secure-random');
var bcrypt = require('bcrypt');
const jwt = require('express-jwt');
const jwt2 = require('jsonwebtoken');
var userSchema = new mongoose.Schema({
username: {type:String,unique:true},
password: String
},{timestamps:true})
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
var signingKey = secureRandom(256, {type: 'Buffer'});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Add headers
app.use(function (req, res, next) {
res.removeHeader('X-Powered-By');
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
var claims = {
iss: "http://example.com/", // The URL of your service
sub: "users/admin1", // The UID of the user in your system
name: "User Name",
scope: "self, admins"
}
userSchema.pre('save', function (next) {
var user = this;
if (!user.isModified('password')) {return next()};
bcrypt.hash(user.password,10).then((hashedPassword) => {
user.password = hashedPassword;
next();
})
}, function (err) {
next(err);
})
userSchema.methods.comparePassword=function(candidatePassword,next){ bcrypt.compare(candidatePassword,this.password,function(err,isMatch){
if(err) return next(err);
next(null,isMatch)
})
}
module.exports = mongoose.model("user", userSchema);
function protectRoute(req,res,next){
// if user exists the token was sent with the request
if(req.user){
//if user exists then go to next middleware
next();
}
// token was not sent with request send error to user
else{
res.status(500).json({error:'login is required'});
}
}
/* app.get('/protected',
jwt({secret: 'shhhhhhared-secret'}),
function(req, res) {
if (!req.user.admin) return res.sendStatus(401);
res.sendStatus(200);
}); */
MongoClient.connect(url, {
useUnifiedTopology: true,
useNewUrlParser: true,
},function(err, db) {
if (err) throw err;
var dbo = db.db("demo");
dbo.collection("demo").find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
});
});
readJsonFile = function(fname, res) {
fs.readFile(fname, 'utf8', function (err,data) {
if (err) {
console.log(err);
}
res.send(data.toString().replace(/\n|\r/g,''));
});
}
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.get('/users', function (req, res) {
MongoClient.connect(url, {
useUnifiedTopology: true,
useNewUrlParser: true,
},function(err, db) {
if (err) throw err;
var dbo = db.db("demo");
dbo.collection("users").find({}).toArray(function(err, result) {
if (err) throw err;
res.send(result);
db.close();
});
});
console.log("GET UserCollection from MongoDB");
});
app.post('/users/:id', verifyToken, function (req, res){
jwt2.verify(req.token, 'secretkey', (err, auth) =>{
if(err){
res.sendStatus(403);
} else {
res.json({
message: 'User created (in theory)',
authData
})
}
})
res.json({
message: 'User created (in theory)2'
})
});
app.post('/api/login', function (req, res){
// Mock user TODO: implement proper BackEnd!
const user = {
id:1,
username:'brad',
email: 'brad#gmail.com'
}
jwt2.sign({user}, 'secretkey', { expiresIn: '1h'}, (err, token) =>{
res.json({
token
});
});
});
app.get('/user', function (req, res) {
readJsonFile('user.json', res);
console.log("GET User");
});
// FORMAT OF TOKEN
// Authorization: Bearer <access_token>
// Verify Token
function verifyToken(req, res, next){
// Get auth header value
const bearerHeader = req.headers['authorization'];
// Check if bearer is undefined
if(typeof bearerHeader !== 'undefined'){
// Split at the space
const bearer = bearerHeader.split(' ');
// Get token from array
const bearerToken = bearer[1];
// Set the token
req.token = bearerToken;
// Next middleware
next();
res.json({message: "Login successful"});
}
else{
// Forbidden
res.sendStatus(403);
next();
}
}
app.listen(3000, function () {
console.log('Listening on port 3000!');
});
if(process.env.NODE_ENV !== 'production') {
process.once('uncaughtException', function(err) {
console.error('FATAL: Uncaught exception.');
console.error(err.stack||err);
setTimeout(function(){
process.exit(1);
}, 100);
});
}
After I run the app and POST the URL /users/5 I get the following errors and the app crashes:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:485:11)
at Array.write (C:\Users\User\Documents\Project\Project2\node_modules\finalhandler\index.js:285:9)
at listener (C:\Users\User\Documents\Project\Project2\node_modules\on-finished\index.js:169:15)
at onFinish (C:\Users\User\Documents\Project\Project2\node_modules\on-finished\index.js:100:5)
at callback (C:\Users\User\Documents\Project\Project2\node_modules\ee-first\index.js:55:10)
at IncomingMessage.onevent (C:\Users\User\Documents\Project\Project2\node_modules\ee-first\index.js:93:5)
at IncomingMessage.emit (events.js:215:7)
at endReadableNT (_stream_readable.js:1183:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
ReferenceError: authData is not defined
at C:\Users\User\Documents\Project\Project2\src\app.js:134:9
at C:\Users\User\Documents\Project\Project2\node_modules\jsonwebtoken\verify.js:223:12
at getSecret (C:\Users\User\Documents\Project\Project2\node_modules\jsonwebtoken\verify.js:90:14)
at Object.module.exports [as verify] (C:\Users\User\Documents\Project\Project2\node_modules\jsonwebtoken\verify.js:94:10)
at C:\Users\User\Documents\Project\Project2\src\app.js:127:8
at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:137:13)
at verifyToken (C:\Users\User\Documents\Project\Project2\src\app.js:178:5)
at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:281:22
at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:354:14)
at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:365:14)
at Function.process_params (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:410:3)
I tried adding return and next statements without any avail.
P.S This helps to understand the problem:
This error occurs when you sent a response before and then you try to send response again. For this you have to check if there is any piece of code that is sending your response twice. Sometimes it happens due to asynchronous behavior of nodejs. Sometimes a process will be in event loop and we send response and when it finishes execution response will be sent again. So You can use callbacks or async await to wait for execution.
PP.S
After following the code examples given in the answers now I get this error (it's more similar to the linked question now):
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:485:11)
at ServerResponse.header (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\response.js:267:15)
at verifyToken (C:\Users\User\Documents\Project\Project2\src\app.js:176:9)
at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:281:22
at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:354:14)
at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:365:14)
at Function.process_params (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:410:3)
at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:275:10)
at C:\Users\User\Documents\Project\Project2\src\app.js:35:3
at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
When your code try to send responce multiple times at that time this error occur,
Here is your working post API code
app.post('/users/:id', verifyToken, function (req, res){
jwt2.verify(req.token, 'secretkey', (err, auth) =>{
if(err){
res.sendStatus(403);
} else {
res.json({
message: 'User created (in theory)',
auth
})
}
})
});
Just remove extra response code from that API
You have to remove next() keywork in verify token function
function verifyToken(req, res, next){
// Get auth header value
const bearerHeader = req.headers['authorization'];
// Check if bearer is undefined
if(typeof bearerHeader !== 'undefined'){
// Split at the space
const bearer = bearerHeader.split(' ');
// Get token from array
const bearerToken = bearer[1];
// Set the token
req.token = bearerToken;
// Next middleware
next();
}
else{
// Forbidden
res.sendStatus(403);
}
}
update verify function with this code
In your app.post('/users/:id'..) you are sending response twice. So, you are getting the error second time because the the response is already send.
There is another error: authData is not defined because it will be auth.
app.post('/users/:id', verifyToken, function (req, res){
jwt2.verify(req.token, 'secretkey', (err, auth) => {
if(err){
res.sendStatus(403);
} else {
res.json({
message: 'User created (in theory)',
auth
})
}
})
});

Node.js - "TypeError - res.setHeader is not a function"

I'm trying to load JSON from a URL to a variable and send it back to the client's javascript
var getJSON =require('get-json');
app.post('/json', function(req, res) {
getJSON(url, function(err, res){
if(err)
{
console.log(err);
}
else
{
res.setHeader('content-type', 'application/json');
res.send(JSON.stringify({json: res.result}));
}
});
});
Every time I run the code the server says that res.setHeader isn't a function and the rest breaks.
Both post and getJSON callbacks have same res variable name.
Try this:
var getJSON =require('get-json');
app.post('/json', function(req, res) {
getJSON(url, function(err, response){
if(err)
{
console.log(err);
}
else
{
res.setHeader('content-type', 'application/json');
res.send(JSON.stringify({json: response.result}));
}
});
});
for me this was happening when fetching data in a forum i built. i found the fix to this in this blogpost:
https://dev.to/shailesh6363/facing-error-res-setheader-not-a-function-2oc9
i added code according to atul singh in the comments.
changes in app.js
app.use((res, next) => {
....
});
to
app.use((req, res, next) => {
....
});
now the app doesnt crash and it sucessfully fetches and displays the data

MEAN CRUD error crash cant set headers

So my CRUD app at this time, does two things, keeps sending an infinite empty list. But not just that, when I try to delete something I get this error... Jump below for the api code. Also if you see anything that might contribute to an infinite list lemme know.
C:\Users\\Desktop\Todo List\node_modules\mongoose\lib\utils.js:419
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:691:11)
at ServerResponse.res.setHeader (C:\Users\\Desktop\Todo List\node_modul
es\express\node_modules\connect\lib\patch.js:63:22)
at ServerResponse.res.set.res.header (C:\Users\\Desktop\Todo List\node_
modules\express\lib\response.js:526:10)
at ServerResponse.res.json (C:\Users\\Desktop\Todo List\node_modules\ex
press\lib\response.js:193:36)
at Promise.<anonymous> (C:\Users\\Desktop\Todo List\routes\api.js:45:21
)
at Promise.<anonymous> (C:\Users\\Desktop\Todo List\node_modules\mongoo
se\node_modules\mpromise\lib\promise.js:162:8)
at Promise.EventEmitter.emit (events.js:95:17)
at Promise.emit (C:\Users\\Desktop\Todo List\node_modules\mongoose\node
_modules\mpromise\lib\promise.js:79:38)
at Promise.fulfill (C:\Users\\Desktop\Todo List\node_modules\mongoose\n
ode_modules\mpromise\lib\promise.js:92:20)
at C:\Users\\Desktop\Todo List\node_modules\mongoose\lib\query.js:1736:
26
routes api code
var Todo = require('../app/models/todos').Todo;
exports.read = function(req, res) {
// use mongoose to get all todos in the database
Todo.find(function(err, todos) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (!err)
res.send(err)
res.json(todos); // return all todos in JSON format
});
};
// create todo and send back all todos after creation
exports.create = function(req, res) {
// create a todo, information comes from AJAX request from Angular
Todo.create({text : req.body.text}, function(err, todos) {
if (err)
res.send(todos);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
};
// delete a todo
exports.delete = function(req, res) {
Todo.remove({_id : req.params._id
}, function(err, todos) {
if (err)
res.send(todos);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
};
//Update a todo
exports.update = function(req, res) {
Todo.findById(req.params._id, function(err, todos){
todos.text = req.body.text;
console.log(todos);
todos.save(function() {
if (!err) {
res.send(todos);
} else if (err) {
res.send(err);
}
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
};
I usually see this error when I'm using res multiple times in my Express route by mistake. Be sure that in route handler (function) you are only using res once.
For example
app.get('/foo', doFoo);
function doFoo(req, res) {
res.send('foo');
res.send('bar');
}
won't work since you're trying to use res twice which internally calls res.end() if I'm not mistaken.
Edit: As it turns out, I think I see the problem in your code.
// create a todo, information comes from AJAX request from Angular
Todo.create({text : req.body.text}, function(err, todos) {
if (err)
res.send(todos);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
Here, you're using res.send(todos) in the event that you receive an error from your first call to Todo.create. Assuming you do receive an error here, your code will still attempt Todo.find. Once that happens, it will then try res.json(todos) thereby firing two responses and resulting in the error that you see about not being able to set response headers after they're already sent. I think you can fix your code by using actual else statements to ensure you don't send two responses.
Todo.create({text:req.body.text}, function(err, todos){
if (err) {...}
else {
.. your else code here
}
});

Categories