I'm trying to send simple form data to a node/express server using AJAX. When submit, I'm brought to a Cannot POST / page and while I'm able to console.log a req, it doesn't include the data from the form. What am I missing?
Form
<form method="POST" class="form-group">
<label for="sentenceCount">Sentences</label>
<input type="number" placeholder="10" name="sentence count" id="sentenceCount" class="form-control parameters">
<button type="submit" id="submit" class="btn btn-primary mt-1">Submit</button>
</form>
AJAX Request
$('button').on('click', function(data) {
$.ajax({
data: data,
url: '/data',
type: "POST"
})
}
)
Server.js
var express = require('express');
var app = express();
app.listen(8000)
app.get('/', function (req, res) {
res.sendFile('/Index.html', {
root: __dirname
})
});
app.post('/data', function (req, res) {
console.log(req)
})
Update:
I've fiddled around and have be able to access a body property but the body is empty and cannot get the input values I need.
AJAX:
$('button').on('click', function(data) {
var formData = $('input').val();
console.log(formData)
$.ajax({
data: formData,
url: '/data',
type: "post"
})
}
)
Server:
app.get('/', function (req, res) {
res.sendFile('/Index.html', {
root: __dirname
})
});
app.use(bodyParser.json())
app.post('/data', function(req, res) {
console.log(req.body)
});
You forgot body parser.
Install body-parser package npm i body-parser
Add body parser JSON middleware before express routes.
Example:
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json())
app.post('/data', (req, res) => {
console.log(req.body);
res.end();
});
And form data should be an object encoded with JSON:
$('button').on('click', function(data) {
var formData = $('input').val();
$.ajax({
data: {value: formData},
url: '/data',
type: "post"
})
}
)
Related
I have two files app.js and test.ejs with code:
app.js
const express = require('express')
const app = express()
app.use(express.urlencoded({ extended: false }));
app.set('view engine', 'ejs')
app.get('/', function (req, res) {
res.render('pages/test'); });
app.post("/", function (request, response) {
console.log(`info - ${request.body.test}`); });
app.listen(3000, console.log('port: 3000'))
test.ejs
...<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>...
...<input id="fn_test" name="test" onkeyup="showResult(this.value)" type="text" required /> ...
... <script>
function showResult(str) {
$.ajax({
url: "/",
method: "POST",
contentType: "application/json",
success: (result) => { }
});
}
...</script>
Console response: info - undefined
I've just started learning Express and Servers.
Problem
Just wanted to load another EJS page onto my localhost:4000/ path as a response after a POST request has been made for a form.
However, although I do get the response of the EJS page with the data from the req.body in the form from the client-side. I can't seem to get the page to load on the browser.
Any ideas? pls help
Express.js Server
let express = require('express');
let app = express();
let bodyParser = require('body-parser');
let path = require('path');
let fs = require('fs');
var urlencodedParser = bodyParser.urlencoded({extended:true});
app.use(express.json());
app.set('view engine', 'ejs');
app.use('/', express.static(__dirname + '/views'));
app.use('/', express.static(__dirname + '/views/partial'));
//Handling the GET request with the render of EJS file "index"
app.get('/', (req, res)=> {
res.render('index');
});
//Handling the POST request from the client, and sending the EJS file "createAccount" as a response
app.post('/', urlencodedParser, (req, res) => {
res.set('cache-control', 'max-age=0; private; no-cache');
res.render('createAccount', {data:req.body}); //
});
app.listen(4000, ()=>{
console.log('Port 4000 has been called');
});
EDIT:
I've included the JS file which I am using to make the POST request below.
document.querySelector('#btn').addEventListener('click', Master);
async function Master(){
console.log("Button clicked")
const username = document.querySelector("#username").value;
const password = document.querySelector("#password").value;
let results = {
"username": username,
"password": password
};
console.log(results);
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(results)
};
const post = await fetch('/', options);
};
I don't know if this is a correct question lol but is it ok to have the same "/" in get and post request? Why not put something in it.
app.post("/create")
then also change this
const post = await fetch('/create', options);
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!");
})
Using Javascript, NodeJS, MongoDB, Express
In my app a user is suppose to type in the input field and when they click the submit button the text gets appended to the page. I am able to successfully post text to the page but when I refresh my browser, my post do not show up. I think I need to do a get request through ajax in the script section of my partials/test.ejs, but I am unsure how to execute this.
models/Blog.js
var
mongoose = require('mongoose'),
Schema = mongoose.Schema,
BlogSchema = new Schema({
name: String
})
var Blog = mongoose.model('Blog', BlogSchema)
module.exports = Blog
views/partials/test.ejs
<body>
<form>
<button type="submit" class="btn btn-default pull-right" id="create">Submit</button>
</form>
<div class="feedback-messages"></div>
</body>
<script type="text/javascript">
var messages = $('.feedback-messages')
var postItem = $("#create")
postItem.on('click', function(evt) {
evt.preventDefault();
$.ajax({
url: '/test',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({data: newItem})
})
.done(function(data) {
console.log("Hello");
messages.append(newItem)
})
routes/index.js
var
express = require('express');
router = express.Router();
bodyParser = require('body-parser');
mongoose = require('mongoose');
Blog = require('../models/Blog.js');
// route for home page
router.get('/', function(req, res) {
res.render('./partials/home');
});
//route for test page
router.get('/test', function(req, res) {
res.render('./partials/test');
});
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false}));
router.get('/test', function(req, res){
Blog.find({}, function(err, blog){
if(err) return console.log(err)
res.json(blog);
})
});
router.post('/test', function(req, res){
// console.log(req.body)
Blog.create({content: req.body.data}, function(err, item){
if(err) return console.log(err)
res.json({serverSays: "Request received. Added item.", item: item})
})
})
module.exports = router;
try changing you code for saving into this
Blog.create({content: req.body.data})
.then(function(item){
res.json({serverSays: "Request received. Added item.", item: item})
})
.catch(function(err) {
return console.log(err)
})
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