I don't get the Bodyparser middleware in Express to work. What can be the problem?
My code:
Node.js:
var express = require('express')
, app = express()
, expressLayouts = require('express-ejs-layouts');
app.set('view engine', 'ejs');
app.set('layout', 'myLayout'); // defaults to 'layout'
app.use(expressLayouts);
app.use(app.router);
app.use(express.bodyParser()); // <- Problem with this
app.get('/', function(req, res){
res.render('aView.ejs', { layout: 'template.ejs' }) // it renders HTML & script
});
app.post('/myroute/', function(req, res) {
console.log("output if this works"); // this works
if(req.body) // this results in false
console.log("From client: "+ req.body.param(1, null) );
else // else is run
console.log("Client to server AJAX doesn't work");
res.send( JSON.stringify({ test : 'Server to client AJAX work'}) ); // works
});
console.log("Node.js server is running");
app.listen(3000);
Client code (jQuery 1.7.1)
function test()
{
alert("this 2"); // this works
getA(function(dat)
{
alert("this 4: "+dat.test); // this works
});
}
function getA(callback) {
$.ajax({
url: '/myroute/',
type: 'POST',
dataType: 'json',
data: ['test 1','2', '4', '6'],
success: function(data) { if ( callback ) callback(data); },
error: function() { if ( callback ) callback(null); },
complete: function() { alert("Klart"); }
});
}
You have the router before the body parser (So by the time it gets to your handler, bodyParser has not been called.) Place bodyParser before app.router
Related
My index.js Server
// USE STRICT;
const express = require('express');
const app = express();
const session = require('express-session');
const http = require('http').Server(app);
const socket = require('socket.io');
const schedule = require('node-schedule');
const cors = require('cors');
const io = socket(http, {
cors: {
origin: 'http://localhost:8080',
methods: ['GET', 'POST'],
allowedHeaders: ['my-custom-header'],
credentials: true
}
});
const port = 8080;
app.use(express.static(__dirname + '/public'));
app.use(express.static(__dirname + '/uploads'));
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const mustacheExpress = require('mustache-express');
app.engine('html', mustacheExpress());
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
const secret = 'somesecretkeyhere';
const passport = require('passport');
const helmet = require('helmet');
const { sendMail } = require('./controllers/sellerAdsController');
// Gives us access to variables set in the .env file via `process.env.VARIABLE_NAME` syntax
// require('dotenv').config();
// Must first load the models before passport
require('./models/user');
// Pass the global passport object into the configuration function
require('./config/passport')(passport);
// This will initialize the passport object on every request
app.use(passport.initialize());
// Allows our remote applications to make HTTP requests to Express application
app.use(cors());
app.use(helmet());
app.use(express.urlencoded({ extended: false }));
// app.use(express.json()); //WARNING: Do not turn on. stops formidable for api calls
app.use(cookieParser(secret));
app.use(session({
secret: secret,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: true
}
}));
app.use(csrf());
// Stop page caching
app.use(function (req, res, next) {
res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
next();
});
// Imports all of the routes from ./routes/index.js
app.use(require('./routes/api/v1'));
// Socket Operations
// io.on('connection', io => {
// let sessionId = io.id;
// io.on('clientHandshake', (data) => {
// console.log(data);
// io.emit('serverHandshake', { sessionId: sessionId });
// });
// });
// io.use((socket, next) => {
// const username = socket.handshake.auth.username;
// if (!username) {
// return next(new Error('invalid username'));
// }
// console.log(username);
// socket.username = username;
// next();
// });
io.on('connection', (socket) => {
console.log('👾 New socket connected! >>', socket.id);
// notify existing users
socket.broadcast.emit('user connected', {
userID: socket.id,
username: socket.username,
});
socket.on('private message', ({ content, to }) => {
socket.to(to).emit('private message', {
content,
from: socket.id,
});
console.log(content, to);
});
});
// EROOR HANDLING ROUTES MUST BE BENEATH ALL APP.USE AND ROUTES
// Check if request is from web or app (HTML/JSON)
// Handle 404
app.use(function (req, res) {
res.status(404);
res.render('404.html', { title: '404: File Not Found' });
});
// Handle 500
app.use(function (error, req, res) {
return res.send(error);
// res.status(500);
// res.render('500.html', { title: '500: Internal Server Error', error: error });
});
// SCHEDULED JOBS
const now = new Date();
let date = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 0, 0);
schedule.scheduleJob(date, sendMail);
http.listen(port, () => {
console.log(`listening on *:${port}`);
});
And this is how I am getting from VUE
window.axios.get('/databank/getCSRF').then((response) => {
window.axios.defaults.headers.common['XSRF-TOKEN'] = response.data;
}, (err) => {
console.log(err)
})
And this is my login request header
XSRF-TOKEN from my login request header sent by axios
So Ive set my server up like that, and my vue SPA, but getCSRF() seems to be getting the request but I can't do a POST request back to the server throws an error
ForbiddenError: invalid csrf token
at csrf
Maybe because you wrote XSRF-TOKEN instead of CSRF-Token as it suggests in the Express Documentation.
I've been trying to get something to send to my shoutbox_endpoint, but on the Express.JS Backend where the endpoint is it returns req.body as undefined
Post Request
const headers = {
"SMN-Auth-JWT": " REDACTED "
};
axios.post(this.endpoint_shoutbox, {
headers: headers,
data: {
user: who,
message: message,
}
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
Backend Endpoint
router.post('/shoutbox-relay', async (req, res) => {
console.log(req.params); // {}
console.log(req.query); // {}
console.log(req.body); // Undefined
});
Main.js
const Logger = require("./LogHandler");
const config = require("../Settings/conf.json");
const Path = require("path");
const ExpressJS = require("express");
const Router = require("./RouterHandler");
const bodyParser = require('body-parser');
const app = ExpressJS();
module.exports.start = async (client) => {
try {
app.set("view engine", "ejs");
app.use("/assets", ExpressJS.static(Path.join(__dirname, "../Website/assets")));
app.use("/socket.io", ExpressJS.static(Path.join(__dirname, "../Website/assets/socket.io")));
app.set("views", Path.join(__dirname, "../Website/views"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.disable("x-powered-by");
app.use(function (req, res, next) {
req.bot = client;
next();
});
app.use("/", Router.index);
app.use("/about", Router.about);
app.use("/chat", Router.chat);
app.use(function (req, res, next) {
var err = new Error("File Not Found");
err.status = 404;
next();
});
const Listener = http.listen(config.Website.port, function () {
Logger.log("Website Handler", "Webserver Started.");
});
} catch (err) {
Logger.error("Website Handler", `Webserver failed to load due to: ${err}`);
}
};
One observation is that, DATA on the client-side JavaScript isn't JSON-stringified. And I would prefer mentioning contentType: 'application/json'
Here is a sample at my end, that's working well with pretty much your configuration.
Client-side JS:
function saveBankDetails() {
someDetails = { bankDetails: {
someKey1: "SOME VALUE 1,
someKey2: "SOME VALUE 2"
}
}
$.ajax({
url: ("SOME PATH"),
method: 'POST',
data: JSON.stringify(someDetails),
contentType: 'application/json'
})
.done(function(data, textStatus, jXhr) {
console.log(data);
})
.fail(function(jXhr) {
console.log('failure')
console.log(jXhr)
});
}
Server-side code:
router.post('SOME PATH', async (req, res) {
console.log(req.body.bankDetails)
});
Output:
{
someKey1: "SOME VALUE 1,
someKey2: "SOME VALUE 2"
}
I am new to Node.js and I have been trying to create a small app integrated with KUE library for task queuing.
When I trying to run the app i.e. node app.js I get the following error:
{ ReplyError: ERR wrong number of arguments for 'set' command
at parseError (.......\node_modules\redis-parser\lib\parser.js:193:12)
at parseType (........\node_modules\redis-parser\lib\parser.js:303:14)
command: 'SET',
args: [ 'promotion:lock', 'H5BCCsomeRandomString==', 'PX', 2000, 'NX' ],
code: 'ERR' }
I did see this error at a lot of places but they all dont seem to be a solution for my problem.
Here is my app.js
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var dotenv = require('dotenv');
dotenv.load();
var queue = require('./routes/queueJob');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/jobs', queue);
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
app.listen(3000);
And here is the routes/queuejob.js
var express = require('express');
var router = express.Router();
var kue = require('kue'),
jobs = kue.createQueue();
var env = {};
jobs.on('ready', () => {
console.info('Queue is ready!');
});
jobs.on('error', (err) => {
console.error('There was an error in the main queue!');
console.error(err);
console.error(err.stack);
});
router.get('/addnewjob', function(req, res) {
let callback = function() {
console.log('Callback has been triggered');
}
newJob('Request Job', callback);
res.end('Successfully added a new job');
});
function newJob(name, callback) {
name = name || 'Default_Name';
var job = jobs.create('new job', {
name: name
});
job
.on('complete', function() {
console.log('Job', job.id, 'with name', job.data.name, 'is done');
callback();
})
.on('failed', function() {
console.log('Job', job.id, 'with name', job.data.name, 'has failed');
callback();
})
job.save();
}
jobs.process('new job', function(job, done) {
setTimeout(function() {
console.log('Job Processing finished');
}, 5000);
done();
});
module.exports = router;
Since there isnt much in the error message I am not sure how to fix this issue. I would really appreciate some help on this.
A SET command in Redis has the following format:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
In your error, it seems that you are trying to use the SET commands with many argurments that do not match the format:
command: 'SET',
args: [ 'promotion:lock', 'H5BCCsomeRandomString==', 'PX', 2000, 'NX' ],
In my node.js app , I'm setting the session using async calls. I have used express-session for the session management. But setting the session behaves occasionally. I'm calling the 2 node.js routes using an angular app.
First time it will call the HTTP get calls and get all the data correctly. But only the last delayed route data will be set to the session. Not data from both route. Seems like setting the data from the delayed route is replacing the fast route session data. Here's my code.
Sometimes all the data is set to the session. (After 2 browser refreshes)
var express = require('express');
var http = require('http');
var request = require('request');
var bodyParser = require('body-parser');
var session = require('express-session');
var ejs = require('ejs');
var cookieParser = require('cookie-parser'); // the session is stored in a cookie, so we use this to parse it
var app = express();
app.set('views', __dirname + '/views');
app.set('port', process.env.PORT || 8081);
app.use(express.static(__dirname + '/app/'));
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.use(cookieParser());
app.use(session({
secret: '232332dfdffd',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 3600000 }}))
app.engine('html', ejs.renderFile);
var server = app.listen(8081,function(){
});
app.get('/route1', function(req, res , next) {
var data1 = req.session.data1;
if(data1){
console.log("Session is not null. Getting data1 from session");
res.status(200);
res.send(data1);
}else{
request({
url: "testUrl",
qs: {},
json: req.body,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}, function(error, response, body){
if(error) {
console.log("error "+error);
res.sendStatus(error);
} else {
req.session.data1 = response;
res.status(response.statusCode);
res.send(response);
}
});
}
});
app.get('/route2', function(req, res , next) {
var data2 = req.session.data2;
if(data2){
console.log("Session is not null. Getting data2 from session");
res.status(200);
res.send(data1);
}else{
request({
url: "testUrl2",
qs: {},
json: req.body,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}, function(error, response, body){
if(error) {
console.log("error "+error);
res.sendStatus(error);
} else {
req.session.data2 = response;
res.status(response.statusCode);
res.send(response);
}
});
}
});
I am trying to implement csrf protection into my project but I can't make it work with jQuery Ajax. (It works with normal posts requests, though)
If I tamper the token using chrome dev tools before I send the form, I still see "data is being processed" text rather than invalid csrf token error.
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var bodyParser = require('body-parser');
var router = express.Router();
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//app.set('strict routing', true);
app.set('view options', {layout: false});
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
var csrfProtection = csrf({ cookie: true });
var parseForm = bodyParser.urlencoded({ extended: false });
app.use(express.static(path.join(__dirname, 'public')));
app.get('/form', csrfProtection, function(req, res) {
// pass the csrfToken to the view
res.render('send', { csrfToken: req.csrfToken() });
});
app.post('/form', parseForm, csrfProtection, function(req, res) {
res.send('data is being processed');
});
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
send.jade
html
head
meta(name='_csrf', content='#{csrfToken}')
body
form(action='/form', method='POST')
| Favorite color:
input(type='text', class="favori", name='favoriteColor')
button(type='submit') Submit
script(src="javascripts/frontend/jquery/jquery-3.0.0-alpha1.js")
script(src="javascripts/test.js")
test.js
$(document).ready(function () {
$.ajaxSetup({
headers: {'X-CSRF-Token': $('meta[name="_csrf"]').attr('content')}
});
$('button').click(function (e) {
e.preventDefault();
var text = $('.favori').val();
alert(text);
$.post(
"/form",
{
text: text
}, function (data) {
console.log(data);
});
});
});
Send the CSRF token inside the payload message:
$('button').click(function (e) {
e.preventDefault();
var text = $('.favori').val();
alert(text);
$.post(
"/form",
{
text: text,
_csrf : $('meta[name="_csrf"]').attr('content')
}, function (data) {
console.log(data);
});
});
To facilitate your work I think you can create a Jquery plugin to do it, something like this:
(function( $ ) {
$.postCSRF = function(to, message, callback) {
message._csrf = $('meta[name="_csrf"]').attr('content');
$.post(to, message, callback);
};
}( jQuery ));
// Usage example:
$.postCSRF('/form',{text:'hi'},function(res) {
console.log(res);
});
Example: http://jsfiddle.net/w7h4Lkxn/
Check the header to see if its passing the tampered token in the cookie or as part of the form data. It looks like your setup is for using cookies. So changing it on the form shouldn't affect the cookie. Lemme know if that helps reveal the issue.
your doing everything exactly right but you have to disable checking for the cookie entirely!
var csrfProtection = csurf({ cookie: false });
the author mentions it here
https://github.com/expressjs/csurf/issues/52
thanks for the above code with the header post as this was crucial for validating the express session token and i have shared it with others