Node.js send data to backend with AJAX - javascript

I'm quite new to AJAX, so sorry for potential missunderstandings, but I'm not completely through that thing.
I'm trying a simple thing. I have a server.js file, which is my backend basically. Then I have a index.html and a script.js. That's all, so a very basic setup. Now, on my script.js, I'm getting some data (a mail address). Now I want to send that data to my backend (into the server.js) to work with it there. How can I do this?
I found some posts already about AJAX with node.js, but I don't get it, especially not where to receive it in my backend. I'm using express for the server by the way.
What I have in my script.js is:
$.ajax({
type: "POST",
url: "server.js",
data: { mail: mail },
success: function(data) {
},
error: function(jqXHR, textStatus, err) {
alert('text status '+textStatus+', err '+err)
}
});
Right so far? How can I now receive the information in my server.js?
There's not much in so far, just:
var express = require('express');
var app = express();
var server = app.listen(3000);
app.use(express.static('public'));
Thanks for any help :)

Note: This was written before the question was updated with the code so the field names and port numbers that I used here as examples may need to be updated with the correct values.
Client-side code - example with jQuery:
$.post('/email', { address: 'xxx#example.com' });
(this can take optional callbacks and it returns a promise that can be used to add a success/error handler)
Server-side code - example with Express:
const express = require('express');
const bodyParser = require('body-parser');
const dir = path.join(__dirname, 'public');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/email', (req, res) => {
// you have address available in req.body:
console.log(req.body.address);
// always send a response:
res.json({ ok: true });
});
app.use(express.static(dir));
app.listen(4443, () => console.log('Listening on http://localhost:4443/'));
This assumes that your static files (HTML, client-side JavaScript, CSS) are in the public directory relative to your server.js file.
See this for background on the JSON/form-encoding issue:
Which method is prefer when building API
See this for background on serving static files:
How to serve an image using nodejs

That's actually quite simple to implement in Express.JS with the basic router:
I'm gonna give you the minified code snippets to help you get sense of how it works across browser and server.
in Front-End, you basically just want to "post" an email address to the backend:
$.post('/email', { email: 'howareyou#xx.com' })
and in Back-End(Express.JS), you should implement the basic router:
var express = require('express');
var app = express();
// use: app.METHOD(PATH, HANDLER)
app.post('/email/', function(req, res) {
var email = req.body.email
})
Read more here: http://expressjs.com/en/guide/routing.html

First, you need a valid route to hit when the server is running. You can do this in server.js through express.
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(express.static('public'));
app.post('/mail', function(req, res) {
var body = req.body;
console.log('email', body.email);
res.json({ message: 'I got the email!' });
});
var server = app.listen(3000);
Notice I have brought in an express middleware that will parse the body for JSON and make it available on the req object under req.body. You will need to install this dependency with npm install --save body-parser.
Then you need to send a POST request to that URL from the front-end.
$.ajax({
type: "POST",
url: "/mail",
data: { mail: mail },
success: function(data) {
console.log('message', data.message);
},
error: function(jqXHR, textStatus, err) {
alert('text status '+textStatus+', err '+err)
}
});
Now, if you submit an email, you should see a log in your terminal that shows the email and a log in your developer console in the browser that shows the message "I got the email!"

in server.js add this :
app.post('/searching', function(req, res){
//do something with req
});
and in script.js :
$.ajax({
type: "POST",
url: "/searching",
data: { mail: mail },
success: function(data) {
},
error: function(jqXHR, textStatus, err) {
alert('text status '+textStatus+', err '+err)
}
});

First of all you nedd to create a route for the Mail
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var app = express();
var router=app.Router();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false })); // Parse request body
app.use(express.static(path.join(__dirname, 'public')));
// Route to check Email
router.post('/CheckEmail',(req,res)=>{
var email=req.body.mail; // Get email here
})
app.listen(process.env.port || 3000,()=>{
console.log('server is running');
})
Ajax
$.ajax({
type: "POST",
url: "/CheckEmail", // post route name here
data: { mail: mail },
success: function(data) {
},
error: function(jqXHR, textStatus, err) {
alert('text status '+textStatus+', err '+err)
}
});

You need a few more things to actually be able to parse the body. Add this to your server.js file.
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
You need to specify a valid URL. Since you are listening on 3000. You also need to specify a route on your server as an endpoint.
$.ajax({
type: "POST",
url: "http:localhost:3000/",
data: { mail: mail },
success: function(data) {
},
error: function(jqXHR, textStatus, err) {
alert('text status '+textStatus+', err '+err)
}
});
Now you need to add a route on your server. You can do so by adding this to your server.js file after all of the app.use calls
app.post("/", function(req, res){
// your logic here
res.send("I am sending something back!");
})

Related

Angular JS to Node Js using Express Js

I have been trying to run a angularJs front-end with NodeJs server with expressJs. This program is merely supposed to takes user input and prints it on the server console. Having limited knowledge in JavaScript I have compiled the following codes:
Client.js
angular.module("appModule",[]).
controller("appController", function($scope,$http){
$scope.action = function () {
console.log($scope.data);
var post = $http({
method: 'POST',
url: '/Data',
data: $scope.mod,
processData: false
})
post.success(function (response) {
console.log(response);
$scope.response.data = response;
});
}
});
Server.js
var express = require('express');
var fs = require("fs");
var url = require("url")
var http = require('http');
var path = require('path');
var bodyParser = require('body-parser');
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/Data', function (req, res) {
console.log(req.body);
res.setHeader('Content-Type', 'application/json');
req.body.serverMessage = "NodeJS replying to angular"
res.end(JSON.stringify(req.body));
});
http.createServer(function(request,response){
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
fs.readFile(pathname.substr(1),function (err,data){
if(err){
console.log(err);
response.writeHead(404, {'Content-Type': 'text/html'});
}else{
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(data.toString());
}
response.end();
});
}).listen(8081, function () {
console.log("Server running at http://127.0.0.1:8081/");
});
This seems to give an error on the terminal:
Server running at http://127.0.0.1:8081/
Request for /public/WebPageView.html received.
Request for /public/JavaScriptCode.js received.
Request for / received.
{ Error: ENOENT: no such file or directory, open ''
at Error (native) errno: -2, code: 'ENOENT', syscall: 'open', path: '' }
The scene of the browser was as follows
Browser Screen
#Ritik Saxena is correct. Also, you're not actually letting Express do it's job in the code you have above as you're not connecting it to the http server at all. the only code of yours actually running is the callback to the http.createServer call.
You should pass the express app to it rather than your own callback. If you want your existing callback to run you need to mount that as app middleware instead.
The last Request in your terminal output shows it receives request for /. Your code extracts / in variable pathname. In fs.readFile you provide first argument as pathname.substr(1) which boils down to null because pathname is / here. Hence, you get the corresponding error.

jQuery Not Working in Express JS - NodeJS

Ok, so I'm new to Express. I'm messing around with sessions and ajax calls, but the problem I'm having is that whenever I run my app, my jquery doesn't work for some reason. This is the code I have:
app.js
var express = require("express");
var mongoose = require("mongoose");
var bodyParser = require("body-parser");
var session = require('express-session')
var app = express();
app.use(express.static("public")); // I understand this is the directory where I would need to put all my static files: css, js, images, etc.
app.set("view engine", "jade");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
//Set secre pass for the session
app.use(session({secret:'password'}));
app.get("/",function(req, res){
if(req.session.userName){
res.render("admin", {session_name: req.session.userName});
}else{
res.render("home");
}
});
app.post("/example-ajax", function(req, res){
res.send(req.body.email); // return the email that was sent by the client
});
app.post("/log-in", function(req, res){
req.session.userName = req.body.name;
res.redirect("/");
});
app.get("/log-out", function(req, res){
req.session.destroy();
res.redirect("/");
});
app.listen(8080);
admin.jade
extends layout_head.jade
block content
div(class="container")
div(class="row")
div(class="col-lg-6 col-lg-offset-3")
h1 Logged In!!
h3 Logged in as: #[b #{session_name}]
a(href="/log-out") Log Out
br
div(class="btn btn-info testAjax") Test Ajax
script(src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js")
script(href="/css/bootstrap/js/bootstrap.min.js")
script(href="/js/main.js")
main.js
$(document).ready(function(){
alert("Loaded");
$(".testAjax").on("click", function(){
alert("test");
$.ajax({
type: 'POST',
url: '/example-ajax',
data: {
email: "admin#yahoo.com"
},
success: function(data){
// data = the email being returned from the server
console.log("Your email is: " + data);
}
});
});
});
So like I said, the jquery doesn't run whenever my page loads up or when I click the testAjax button. When I check the console, it doesn't give me any errors so I don't know what is causing the problem.
My second question is: Is this the right way to make ajax calls in Express?
Any help is greatly appreciated. Thanks.
I just needed to change href to src in the script tags.

How could node.js server access the ajax request's data?

Below are my Server's code
/* GET tone. */
router.post('/tone', function(req, res, next) {
console.log("what is the body" + req.body.data);
tone_analyzer.tone({ text: req.body.data }, function(err, tone) {
console.log(req.body.data);
if (err) {
console.log(err);
} else {
res.send(JSON.stringify(tone, null, 2));
}
console.log(req);
});
});
My Ajax's call in the html page.
function toneAnalysis(info){
$.ajax({
url: 'http://localhost:3000/tone',
type: 'POST',
data: info,
success: function(res) {
console.log("testing " + info);
},
error: function(xhr, status, errorThrown) {
console.log(status);
}
})
The server could not retrieve the req.body.data. When I tried to console log it, it always prints undefined. Could any one help me out with this? Thank you.
Update:
The printed req.body after I used body parser
Like the answer above mentioned you can use BodyParser and you can download it and install it using npm like so:
# npm install bodyparser --save
Then returning to your $.ajax call, you are sending some data represented in the data object, so using the BodyParser you can simply have an access to the sent object, because BodyParser add another object to the req nodejs object and it's called body, so if you want to access to all sent items using BodyParser you will probably going to do it like so :
const app = require('express')();
let bodyParser = require('body-parser');
// add a new middleware to your application with the help of BodyParser
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
//Configure the route
router.post('/tone', (req, res, next) => {
console.log("what is the body" + req.body.data);
tone_analyzer.tone({ text: req.body.data}, (err, tone) => {
console.log(req.body.data);
if (err){
console.log(err);
}
else{
res.send(JSON.stringify(tone, null, 2));
}
console.log(req);
});
});
Now using BodyParser, things can get really easy when you handle your XHR or HTTP calls.
your request body will be in req.body
if it is json you can use
let bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
router.post('/tone', function(req, res, next) {
console.log("what is the body" + req.body);
tone_analyzer.tone({ text: req.body},
function(err, tone) {
// your code here
}
Do you have this in your server configuration?
app.use(express.bodyParser());
This allows you to parse JSON requests.

Node Express and csurf - 403 (Forbidden) invalid csrf token

Looked through and tried everything I could find on here, and elsewhere by Googling...and I'm just not able to get past this. I'm using Node, Express, EJS, and attempting to use csurf on a form, that is posted w/ jQuery ajax. No matter how I configure csurf, I get "403 (Forbidden) invalid csrf token"
I've tried configuring both globally in app.js and in the controller. Here's what I tried in app.js:
var express = require('express');
var session = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mysql = require('mysql');
var flash = require("connect-flash");
var csrf = require("csurf");
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(session({
secret: 'somethingsecret',
resave: true,
saveUninitialized: true,
httpOnly: true,
secure: false
}));
app.use(csrf());
app.use(function (req, res, next) {
var token = req.csrfToken();
res.cookie('XSRF-TOKEN', token);
res.locals.csrfToken = token;
console.log("csrf token = " + token);
next();
});
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err);
// handle CSRF token errors here
res.status(403);
res.send('form tampered with');
})
//routing
var routes = require('./routes/index');
var users = require('./routes/users');
var register = require('./routes/register');
app.use('/', routes);
app.use('/users', users);
app.use('/register', register);
...with this controller:
var express = require("express");
var router = express.Router();
var bodyParser = require("body-parser");
var userSvc = require("../service/userservice");
var jsonParser = bodyParser.json();
router.get("/", function(req, res, next) {
console.log("token = " + token);
userSvc.getAllPublicRoles(function(data) {
res.render("register", {
title: "Register a new account",
roles: data
});
});
});
router.post("/new", jsonParser, function(req, res, next) {
userSvc.addUser(req.body, function(result) {
console.log("New user id = " + result.insertId);
res.send('{"success" : "Updated Successfully", "status" : 200}');
});
});
...and this view:
form:
<form id="registerForm" class="form-horizontal" method="post">
<input type="hidden" name="_csrf" value="<%= csrfToken %>" />
ajax call:
$.ajax({
url: "/register/new",
type: "POST",
dataType: "json",
data: user
}).done(function(data) {
if (data) {
console.log("Success! = " + data);
}
}).fail(function(data) {
console.log("Something went wrong: " + data.responseText);
});
Then I just tried just doing everything in the controller, removing all references, calls, etc. from app.js, and using the same form and ajax call as above:
var express = require("express");
var router = express.Router();
var bodyParser = require("body-parser");
var csrf = require("csurf");
var userSvc = require("../service/userservice");
var csrfProtection = csrf();
var jsonParser = bodyParser.json();
router.get("/", csrfProtection, function(req, res, next) {
var token = req.csrfToken();
console.log("token = " + token);
userSvc.getAllPublicRoles(function(data) {
res.render("register", {
title: "Register a new account",
csrfToken: token,
roles: data
});
});
});
router.post("/new", jsonParser, csrfProtection, function(req, res, next) {
userSvc.addUser(req.body, function(result) {
console.log("New user id = " + result.insertId);
res.send('{"success" : "Updated Successfully", "status" : 200}');
});
});
Not sure where to go from here. I've been using node for about two weeks, in my spare time, so pardon my ignorance here.
If you want to store the token in a cookie instead of the session, let csurf create the cookie for you e.g.
// Store the token in a cookie called '_csrf'
app.use(csrf({cookie: true));
// Make the token available to all views
app.use(function (req, res, next){
res.locals._csrf = req.csrfToken();
next();
});
Then you need to make sure the token is available when you're making the call using AJAX either via the POST'ed data, or as a custom request header such as 'xsrf-token'.
At the minute, you're providing the token to the form, but not the actual request (sent using AJAX).
For example, you could render the token in the AJAX setup:
$.ajaxSetup({
headers: {"X-CSRF-Token": "{{csrfToken}}" }
});
After several more hours of troubleshooting and searching, I found a post that helped answer it. All I needed was to pass the header value in the ajax post. Makes sense, I just overlooked it. Like so:
<input type="hidden" id="_csrf" name="_csrf" value="<%= csrfToken %>" />
...and then in jQuery:
$.ajaxSetup({
headers: {"X-CSRF-Token": $("#_csrf").val()}
});
An another approach over my personal project is to resend a new token when I sucessfully submit my form:
For example over my form (that does file upload) I have the follwing html:
<form id="upload_form" type="multipart/form-data" data-csrf="{{csrfToken}}" method="post" action="/data_assets">
<input id="excell_upload" type="file" style="visible:hidden" name="data_assets"/>
</form>
And on file change I trigger the upload like that:
$('#excell_upload').on('change',function(event){
event.preventDefault();
var formData = new FormData($("#upload_form")[0]);
$.ajax({
'type':$("#upload_form").attr('method'),
'data': formData,
'url': $("#upload_form").attr('action'),
'processData': false,
'contentType': false,
'mimeType': 'multipart/form-data',
'headers': {"X-CSRF-Token": $("#upload_form").attr('data-csrf') },
'beforeSend': function (x) {
if (x && x.overrideMimeType) {
x.overrideMimeType("multipart/form-data");
}
$('#trigger_upload').addClass('disabled');
},
'success':function(data){
$('#upload_form').attr('data-csrf',data.csrfToken)
},
'fail':function(){
},
'complete':function(){
$('#trigger_upload').removeClass('disabled');
}
});
});
As you notice I receive a new csrf token in order to be able to reuse my form for new submits. I regenerate the CSRF token like that:
app.post('/data_assets',function(req,res,next){
res.json({'csrfToken':req.csrfToken()});
});
other than adding the "X-CSRF-Token" to the header on post you want to disable cookies entirely!
var csrfProtection = csurf({ cookie: false });
the author mentions it here
https://github.com/expressjs/csurf/issues/52
cookie and session validation should not be combined -- although it is a bit misleading since he has combined cookie and session validation in his documentation:
https://github.com/expressjs/csurf#simple-express-example

Parsing POST data with body-parser in Node.js app

I am trying to build a simple Node.js app which will parse data passed to it as POST requests from my AngularJS app. Below is the code used in my AngularJS app and my Node.js app. Problem I am facing is that I've searched the web trying to find how to parse (data and header) information passed in POST requests but failed to find any example, so any help with an example of parsing (data and header) passed in POST requests will help me a lot. Thanks.
Note: I am using express 4.1.2, body-parser 1.8.0.
Node app:
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(bodyParser.json());
app.post('/', function (req, res) {
console.log(req.body);
res.send(200);
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Server listening on port ' + app.get('port'));
});
POST request code
var deferred = $q.defer();
var dataObj = {};
dataObj.name = 'Chan';
dataObj.email_address = 'email#domain.com';
var myToken = '1234567890';
$http({ method:'POST',
url: '/',
data: dataObj,
headers: { 'Token' : myToken
}
}).success(function(data,status,headers,config){
deferred.resolve(data);
}).error(function(data,status,headers,config){
deferred.reject(status);
});
return deferred.promise;
If you're setting data to a plain js object, angular is interpreting that as a urlencoded form with the various keys and values in that object.
So there's two possible fixes here. One is to add something like app.use(bodyParser.urlencoded({ extended: false })); after app.use(bodyParser.json());
The second possible fix is to change your $http call to post JSON instead of urlencoded data. For that, change data: dataObj, to data: JSON.stringify(dataObj), and add 'Content-Type': 'application/json' to your headers so that it looks like this:
headers: {
'Token' : myToken,
'Content-Type': 'application/json'
}

Categories