I have a node server and an angularJS app.
I have a route to get informations about one record.
The route is '/pacientes/:id'
When I request data from that route i am getting an error.
What am I doing wrong?
//error:
Error: Can't set headers after they are sent.
at ServerResponse.setHeader (_http_outgoing.js:367:11)
at ServerResponse.header (C:\nodeapp\cloudapp\node_modules\express\lib\respo
nse.js:719:10)
at ServerResponse.send (C:\nodeapp\cloudapp\node_modules\express\lib\respons
e.js:164:12)
at ServerResponse.json (C:\nodeapp\cloudapp\node_modules\express\lib\respons
e.js:250:15)
at C:\nodeapp\cloudapp\server.js:973:10
at Array.forEach (native)
at C:\nodeapp\cloudapp\server.js:971:13
at Layer.handle [as handle_request] (C:\nodeapp\cloudapp\node_modules\expres
s\lib\router\layer.js:95:5)
at next (C:\nodeapp\cloudapp\node_modules\express\lib\router\route.js:131:13
)
at Route.dispatch (C:\nodeapp\cloudapp\node_modules\express\lib\router\route
.js:112:3)
Here is app controller:
angular.module("clinang").controller('ProcedimentosCtrl',['$scope','$http','$state',function($scope,$http,$state){
$scope.modelo={}
var tipoId=$state.params.tipoId;
if (tipoId) {
$http.get('/pacientes/' + tipoId).then(function(response){
$scope.modelo=response.data;
}, function(error){
console.log(error)
});
}
}]);
node - server.js
var express = require('express');
var bodyParser = require('body-parser');
var jwt = require('jsonwebtoken');
var expressJwt = require('express-jwt');
var path = require('path');
var app = express();
// Define the port to run on
app.set('port', process.env.port || 80);
app.use(bodyParser.json());
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
var pacientes=[
{id:1, nome:'Joao'},
{id:2, nome:'Maria'}
];
app.get('/pacientes/:id', function(req, res) {
pacientes.forEach(function (paciente) {
if (paciente.id == req.params.id) {
res.json(paciente);
return;
}
});
res.status(404).end();
});
//The 404 Route (ALWAYS Keep this as the last route)
app.get('*', function(req, res){
res.status(404).end();
});
// Listen for requests
var server = app.listen(app.get('port'), function() {
var port = server.address().port;
console.log('Magic happens on port ' + port);
});
You are trying to send multiple responses to the same request from the client, but you can only send it once.
Change this:
pacientes.forEach(function (paciente) {
if (paciente.id == req.params.id) {
res.json(paciente);
return;
}
});
To this:
var result;
pacientes.forEach(function (paciente) {
if (paciente.id == req.params.id) {
result = paciente;
}
});
if (result !== undefined) {
res.json(result);
} else {
res.sendStatus(404);
}
The functions res.json, and res.sendStatus sets the header and the response's body, and call the .end() function after that, so you don't need to do it.
Related
I am new to node and I am building rest node API.I am using express for HTTP and JWT for authentication. Whenever I request /node/me with header 'x-auth'.
It's giving error which is given below. I have set up middleware in /node/me
which query mogodb database. It finds user using header 'x-auth'
server.js:
var env = process.env.NODE_ENV || 'development';
if (env === "development") {
process.env.PORT = 3000;
process.env.MONGODB_URI = 'mongodb://localhost:27017/TodoApp';
} else if (env === "test") {
process.env.PORT = 3000;
process.env.MONGODB_URI = 'mongodb://localhost:27017/TodoAppTest';
}
var _ = require('lodash');
var express = require('express');
var bodyParser = require('body-parser');
var {ObjectID} = require('mongodb');
var app = express();
var {mongoose} = require('./db/mongoose');
var {Todo} = require('./models/todo');
var {User} = require('./models/user');
const {authenticate} = require('./middleware/authenticate');
const bcrypt = require('bcryptjs');
const port = process.env.PORT;
app.use(bodyParser.json());
app.get('/users/me',authenticate,(req,res) => {
res.send(req.user);
});
module.exports = {
app,
env
}
app.listen(port,() => {
console.log(`server is running ${port}`);
});
authenticate.js:
const {User} = require('./../models/user');
var authenticate = (req,res,next) => {
var token = req.header('x-auth');
User.findByToken(token).then((doc) => {
if (!doc) {
res.status(401).send('doc is not found');
}
req.token = token;
req.user = doc;
next();
}).catch((e) => {
res.status(401).send(e);
});
I am getting this error about headers
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
at ServerResponse.setHeader (_http_outgoing.js:501:3)
at ServerResponse.header (C:\Users\Yash\Desktop\node-api\node_modules\express\lib\response.js:719:10)
at ServerResponse.send (C:\Users\Yash\Desktop\node-api\node_modules\express\lib\response.js:164:12)
at app.get (C:\Users\Yash\Desktop\node-api\server\server.js:254:5)
at Layer.handle [as handle_request] (C:\Users\Yash\Desktop\node-api\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Yash\Desktop\node-api\node_modules\express\lib\router\route.js:131:13)
at User.findByToken.then (C:\Users\Yash\Desktop\node-api\server\middleware\authenticate.js:19:2)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
You must change to this:
if(!doc) {
res.status(401).send('doc is not found');
} else {
req.token = token;
req.user = doc;
next();
}
The reason is after the if inside code is executed the flow continues independently if you are sending a response because it is just a function call. So you are executing the error code and after that you are executing the success code, I mean the next function like if the doc exists and at the moment of the next() execution the response has been sent.
Regards,
You can only send one response with express. If you follow the series of events in your Authenticate middleware you'll discover that you are sending a response with:
res.status(401).send('doc is not found');
and then calling next(). When you call next it passes control over to the next middleware, which then sends:
res.send(req.user);
Cut the next() out of the loop when the request fails with something like:
if(!doc){
res.status(401).send('doc is not found');
return;
}
You must export authenticate. And add return
if(!doc) {
res.status(401).send('doc is not found');
return;
}
or add else
if(!doc) {
res.status(401).send('doc is not found');
} else {
req.token = token;
req.user = doc;
next();
}
I'm trying to get a polymer web page login to work but seemingly I can't since app.js cannot read the JSON database defined within the file itself. I have uploaded a screenshot of how my folders and files are layered in Visual Studio Code. I'm using a Windows 10 NT OS and Git Bash to run my commands.
THIS IS THE GIT BASH ERROR
Rhino#DESKTOP-NB42TJJ MINGW64
/c/users/rhino/documents/work/personal/polymer-project $ node
demo-server/app.js JSON Server is runnning TypeError: Cannot read
property 'users' of undefined
at C:\users\rhino\documents\work\personal\polymer-project\demo-server\app.js:34:33
at Layer.handle [as handle_request] (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\layer.js:95:5)
at next (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\route.js:131:13)
at Route.dispatch (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\layer.js:95:5)
at C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\index.js:277:22
at Function.process_params (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\index.js:330:12)
at next (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\index.js:271:10)
at C:\users\rhino\documents\work\personal\polymer-project\demo-server\app.js:29:9
at Layer.handle [as handle_request] (C:\users\rhino\documents\work\personal\polymer-project\node_modules\express\lib\router\layer.js:95:5)
THIS IS MY app.js file
var express = require("../node_modules/express");
var app = express();
var path = require("path");
var jsonServer = require("../node_modules/json-server");
var server = jsonServer.create();
var router = jsonServer.router('db.json');
//Authentication Libraries - Start
var cookieParser = require('../node_modules/cookie-parser');
var session = require('../node_modules/express-session');
//Authentication Libraries - End
server.use(cookieParser("security", {"path": "/"}));
app.use(cookieParser("security", {"path": "/"}));
server.use(function(req, res, next) {
res.setHeader("Access
-Control-Allow-Origin", "http://localhost:8080");
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
res.setHeader("Access-Control-Expose-Headers","Access-Control-Allow-Origin");
res.setHeader("Access-Control-Allow-Headers",
"X-Custom-Header,X-Requested-With,X-Prototype-Version,Content-Type,Cache- Control,Pragma,Origin,content-type");
if (!req.signedCookies.usersession && req._parsedUrl.pathname != "/auth/login" && req.method != "OPTIONS") {
res.redirect('http://localhost:8080/app/pages/auth/auth.html');
}else{
next();
}
});
server.post('/auth/login', function(req, res){
var users = router.db.object.users;
var username = req.query.username;
var password = req.query.password;
for(var i=0;i<=users.length -1;i++){
if(users[i].username == username && users[i].password == password) {
res.cookie('usersession', users[i].id, {maxAge: 9000000, httpOnly: false, signed: true});
res.send(JSON.stringify({success: true}));
return;
}
}
res.send(JSON.stringify({ success: false, error: 'Wrong username or password' }));
});
app.get('/', function(req, res){
if (!req.signedCookies.usersession) {
res.redirect('app/pages/auth/auth.html');
}else{
res.sendFile(path.join(__dirname+'/../app/index.html'));
}
});
app.get('/auth/logout', function(req, res){
res.clearCookie('usersession');
res.redirect('/app/pages/auth/auth.html');
});
/*app.get('/', function(req, res){
res.sendFile(path.join(__dirname+'/../app/index.html'));
});
*/
app.use(express.static(path.join(__dirname, '../')));
var http = require('http').Server(app);
http.listen(8080);
server.use(jsonServer.defaults); //logger, static and cors middlewares
server.use(router); //Mount router on '/'
server.listen(5000, function () {
console.log('JSON Server is runnning')
});
Picture of Visual Studio Code project folder structure
You may need to add middleware as follow in your code:
var jsonServer = require('../node_modules/json-server');
var server = jsonServer.create();
var router = jsonServer.router('db.json');
var middlewares = jsonServer.defaults(); //<--- new line
then in your server.use(jsonServer.defaults); //logger, static and cors middlewares, inject middleware as shown:
server.use(middlewares); //logger, static and cors middleware
When i am trying to launch my nodejs server, it does not call the client/public folder. I get the below error, when i point to http://localhost:3000
Error: Not found at
/home/shankar/projects/apiDocs/server/server.js:36:12 at
Layer.handle [as handle_request]
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:312:13)
at
/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:280:7
at Function.process_params
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:330:12)
at next
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:271:10)
at
/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:618:15
at next
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:256:14)
at Function.handle
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:176:3)
at router
(/home/shankar/projects/apiDocs/node_modules/express/lib/router/index.js:46:12)
Below is my server.js code
var express = require('express');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app = express();
app.use(express.static(path.join(__dirname, "public")));
app.use(logger('dev'));
app.use(bodyParser.json({limit: '50mb'}));
mongoose.connect('mongodb://127.0.0.1:27017/app', function (error) {
if (error) {
console.log(error);
}
});
app.all('/*', function(req, res, next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-type,Accept,X-Access-Token,X-Key");
if(req.method === 'OPTIONS'){
res.status(200).end();
} else {
next();
}
});
app.all("/api/v1/*", [require('./middlewares/validateRequest')]);
app.use("/", require("./routes"));
app.use(function(req, res, next){
var err = new Error("Not found");
err.status = 404;
next(err);
});
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + server.address().port);
});
I am trying to run my client and my restful services on same server, when i launch my server on port 3000, i expect the client and server to be on the same server.
Folder Structure:
/app
--node-modules
--public
--app //contains all angularjs related files
--assets //contains images and js libraries
--index.html
--server
--server.js
try to use this :
app.use(express.static('./.'));
this is should let express able to see your files
i have the following method to auth my users:
app.all('/*', function(req, res, next) {
// CORS headers
res.header("Access-Control-Allow-Origin", "*"); // restrict it to the required domain
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
// Set custom headers for CORS
res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
if (req.method == 'OPTIONS') {
res.status(200).end();
} else {
next();
}
});
var auth = require('./auth.js');
router.post('/login', auth.login);
app.all('/api/*', [require('./middlewares/validateRequest')]);
// If no route is matched by now, it must be a 404
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
And my Auth.js
var jwt = require('jwt-simple');
var auth = {
login: function(req, res) {
var username = req.body.username || '';
var password = req.body.password || '';
if (username == '' || password == '') {
res.status(401);
res.json({
"status": 401,
"message": "Invalid credentials"
});
return;
}
// Fire a query to your DB and check if the credentials are valid
var dbUserObj = auth.validate(username, password);
if (!dbUserObj) { // If authentication fails, we send a 401 back
res.status(401);
res.json({
"status": 401,
"message": "Invalid credentials"
});
return;
}
if (dbUserObj) {
// If authentication is success, we will generate a token
// and dispatch it to the client
res.json(genToken(dbUserObj));
}
},
validate: function(username, password) {
// spoofing the DB response for simplicity
var dbUserObj = { // spoofing a userobject from the DB.
name: 'arvind',
role: 'admin',
username: 'arvind#myapp.com'
};
return dbUserObj;
},
validateUser: function(username) {
// spoofing the DB response for simplicity
var dbUserObj = { // spoofing a userobject from the DB.
name: 'arvind',
role: 'admin',
username: 'arvind#myapp.com'
};
return dbUserObj;
}
}
// private method
function genToken(user) {
var expires = expiresIn(7); // 7 days
var token = jwt.encode({
exp: expires
}, require('../config/secret')());
return {
token: token,
expires: expires,
user: user
};
}
function expiresIn(numDays) {
var dateObj = new Date();
return dateObj.setDate(dateObj.getDate() + numDays);
}
module.exports = auth;
This server runs on port 8080.
So when i attempt to go to http://localhost:8080/login i get the following error message:
Error: Not Found
at app.use.bodyParser.urlencoded.extended (/var/www/example/backend/server.js:34:15)
at Layer.handle [as handle_request] (/var/www/example/backend/node_modules/express/lib/router/layer.js:82:5)
at trim_prefix (/var/www/example/backend/node_modules/express/lib/router/index.js:302:13)
at /var/www/example/backend/node_modules/express/lib/router/index.js:270:7
at Function.proto.process_params (/var/www/example/backend/node_modules/express/lib/router/index.js:321:12)
at next (/var/www/example/backend/node_modules/express/lib/router/index.js:261:10)
at next (/var/www/example/backend/node_modules/express/lib/router/route.js:100:14)
at next (/var/www/example/backend/node_modules/express/lib/router/route.js:104:14)
at next (/var/www/example/backend/node_modules/express/lib/router/route.js:104:14)
at next (/var/www/example/backend/node_modules/express/lib/router/route.js:104:14)
However it seems that the rest of my auth is working because if i go to:
http://localhost:8080/api/user
I get: {"status":401,"message":"Invalid Token or Key"}
Can anyone tell me why my login does not work?
Full server script:
// BASE SETUP
// =============================================================================
var express = require('express'),
bodyParser = require('body-parser');
var app = express();
var router = express.Router();
var es = require('express-sequelize');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// =============================================================================
//Secure
app.all('/*', function(req, res, next) {
// CORS headers
res.header("Access-Control-Allow-Origin", "*"); // restrict it to the required domain
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
// Set custom headers for CORS
res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
if (req.method == 'OPTIONS') {
res.status(200).end();
} else {
next();
}
});
var auth = require('./auth.js');
router.post('/login', auth.login);
app.all('/api/*', [require('./middlewares/validateRequest')]);
// If no route is matched by now, it must be a 404
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
var env = app.get('env') == 'development' ? 'dev' : app.get('env');
var port = process.env.PORT || 8080;
var Sequelize = require('sequelize');
// db config
var env = "dev";
var config = require('./database.json')[env];
var password = config.password ? config.password : null;
// initialize database connection
var sequelize = new Sequelize(
config.database,
config.user,
config.password,
{
logging: console.log,
define: {
timestamps: false
}
}
);
//Init models
var division_model = require('./lb_models/division/division_model')(express,sequelize,router);
var user_model = require('./lb_models/user/user_model')(express,sequelize,router);
var team_model = require('./lb_models/Team')(express,sequelize,router);
app.use('/api', router);
app.use(division_model);
app.use(user_model);
app.use(team_model);
// START THE SERVER
app.listen(port);
console.log('Magic happens on port ' + port);
Try moving your app.use(bodyParser…) statements above the login route. The order of middleware matters. At the time login is called the req object hasn't run through the bodyParser middleware yet.
Also, your router instance is mounted at "/api" so the router methods will never get called for "/login". The following line should be place above your 404 catchall:
app.use('/', router);
Before, you had used app.use('/api', router), which means that your router routes will only be looked at for any request that starts with '/api'. Also, you had place the 'use' statement too far down.
When setting up middleware, the order in which you call app.use() is key. In your server.js, you're setting up your application routes before you set up body parser. Meaning, when the request comes in, is is not parsed before hitting your application logic. You need to move the app.use(bodyParser) parts to the top of your code.
var express = require('express'),
bodyParser = require('body-parser');
var app = express();
var router = express.Router();
var es = require('express-sequelize');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
perphaps you have to move the
app.use("/", (req, res, next) => {
res.status("404").json({message: "Not found"})
})
to the bottom of your code, but before "app.listen()", The order you declare the routes in the router are important, so putting the "app.use" after you declare all theses routes, would search a match with all the previous route and if none is found then it will enter in that last one
Like this:
.
..
...
app.use('/api', router);
app.use(division_model);
app.use(user_model);
app.use(team_model);
app.use("/", (req, res, next) => {
res.status("404").json({message: "Not found"})
})
// START THE SERVER
app.listen(port);
console.log('Magic happens on port ' + port);
I have built few rest API on server and calling them from other domain the Get request is working fine but I am facing an issue in calling the POST request.
I am unable to receive data on server send by the clients.
Server Code:
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
//var fn = require('fn')
var app = express();
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
// intercept OPTIONS method
if ('OPTIONS' === req.method) {
res.send(200);
}
else {
next();
}
};
// all environments
app.set('port', process.env.PORT || 3000);
app.use(allowCrossDomain);
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.post('/user', user.saveUser);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
exports.saveUser = function(req, res) {
var key = req.body.key; //fb,twitter,web
var userData = req.body.userData;
var result = checkUser(userData,key);
}
Clients code where the request is made :
var data = { key: 'web', userData: userData }
$.ajax({
method: "POST",
//contentType: 'application/json',
url: "www.acbd.com/user",
//url:"http://prayable-21641.onmodulus.net/user",
data: data,
crossDomain: true,
dataType: "json"
}).success(function (data, textstatus) {
// this callback will be called asynchronously
// when the response is available
console.log(data)
console.log(textstatus)
}).error(function (data, textstatus) {
console.log(data)
console.log(textstatus)
// called asynchronously if an error occurs
// or server returns response with an error status.
});
I am unable to get key or userData on server, it say they are not defined:
TypeError: Cannot read property 'key' of undefined
You forgot to require and use the body-parser middleware module.
And also, why is content-type commented out? You need it
Server code should look like this:
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
//var fn = require('fn')
//requiring body-parser
var bodyParser = require('body-parser');
var app = express();
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
// intercept OPTIONS method
if ('OPTIONS' === req.method) {
res.send(200);
}
else {
next();
}
};
// all environments
app.set('port', process.env.PORT || 3000);
app.use(allowCrossDomain);
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
// using body-parser
app.use(bodyParser());
app.post('/user', user.saveUser);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
also, don't forget to npm install it:
npm install body-parser
//REquire the body parser, make sure you install it using
npm install body-parser
var bodyParser = require('body-parser');
and then use it
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
Hope that helps