I'm trying to use a simple POST request with Node using Express and instead am getting cannot POST with a 404. In the end I want to use ajax so it POSTs without refreshing the page in the browser, but first I need to get it running like this and I can't figure out what I've gotten wrong.
public/form.html
<!DOCTYPE html>
<form method="POST" action="">
<input name="firstName">
<input name="lastName">
<input type="submit">
</form>
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
//server running?
app.listen(3000,() => {
console.log('Started on PORT 3000');
})
//Serve the web page directory
app.use(express.static('./public'))
//Return form fields
app.post('form.html', (req, res) => {
console.log("First name: " + req.body.firstName)
console.log("Last name: " + req.body.lastName)
res.end()
})
app.post("/api", (req, res) => {
console.log("First name: " + req.body.firstName);
console.log("Last name: " + req.body.lastName);
res.end();
});
Here you have to make POST request to /api
<form method="POST" action="/api">
I've figured it out and will share in case others are looking for the same thing. The other responses are correct, but I was looking to POST without changing the URL. This doesn't look to be possible because I always get cannot POST and a 404 if I point to the existing page (either leaving action empty or using "#").
However, when you use AJAX, you still point to a new URL with the form action attribute and in your node app, but your AJAX code will keep the URL on the same page (the page doesn't refresh).
Related
I know there are plenty of similar questions like my, but I couldn't find any solution for my problem.
I think the issue is that am not getting the product.html and I assume that there is also a problem with the redirection to the product.html.
product.html
<!DOCTYPE html>
<html>
<head>
<title>Product</title>
<meta charset="utf-8" />
</head>
<body>
<form id="product" action="/information" method="POST">
<label for="product_id">Enter product ID: </label>
<input id="product_id" name="product_id" type="text" required />
<input type="submit" />
</form>
</body>
</html>
index.js
const express = require("express");
// load data
const products = require("./data.json");
const app = express();
// static files
app.use(express.static("public"));
// form middleware
app.use(express.urlencoded({ extended: true }));
app.post("/information", (req, res) => {
// ES6 deconstruction syntax, get user input
const { product_id } = req.body;
// search product array
const product = products.find((product) => product.Product_ID === product_id);
if (product) res.json(product);
else res.send("product not found");
});
// redirect all GET requests to product form
app.get("*", (req, res) => {
res.redirect("/product.html");
});
app.listen(8000,console.log(`App listening at http://localhost:8000`));
When I run the code like above, I get the following error: The page isn’t redirecting properly
(Cookies & Cache is deleted). I even tried another project with a node.js server and the localhost in Firefox worked.
When I command the redirection out, I get this error: Cannot GET /
When I use "/" instead of "*" in the redirections, this error appears: Cannot GET /product.html
I don't understand why it doesn't get the product.html and why the redirection doesn't work right.
To render product.html for every endpoint, you can use sendFile rather than redirect, you will need to use path module, which is a core module to resolve the path to html file:
const path = require('path');
//your code
app.get('*', (req, res)=> {
//note that product.html file is in the same directory or you specify
//its relative path
res.sendFile(path.resolve(__dirname, 'product.html'))
})
I've tried many StackOverflow answers, and this method normally works using body-parser, however I've been having issues with getting any output from req.body with either AJAX or form data.
In server.js:
app.use(helmet()); // Helmet middleware
app.use('/assets', express.static('resources/web/assets')); // Makes /assets public
app.use(require('./resources/modules/session.js')); // Custom session middleware
app.set('view engine', 'ejs'); // Sets EJS to the view engine
app.set('views', `${__dirname}/resources/web/pages`); // Sets the views folder
app.use(cookieParser()); // cookie-parser middleware
app.use(bodyParser.urlencoded({ extended: true })); // body-parser's middleware to handle encoded data
app.use(bodyParser.json()); // body-parser's middleware to handle JSON
app.use(fileUpload({ limits: { fileSize: 100 * 1024 * 1024 } })); // express-fileupload middleware (bushboy wrapper)
app.use('/api', require('./resources/routes/api.js')); // External API router
// ...
app.post('/login', (req, res) => {
console.log(req.body);
res.render('login', {
config,
page: {
name: 'Login'
},
error: ''
});
res.end();
});
My login.ejs code:
<form method="POST">
<div class="input-group">
<i class="las la-user"></i>
<input placeholder="Username" name="username" type="text" required>
</div>
<div class="input-group">
<i class="las la-lock"></i>
<input placeholder="Password" name="password" type="password" required>
</div>
<button type="submit">
<i class="las la-paper-plane"></i> Login
</button>
</form>
No matter what I try, I always get an empty {} in the console with no avail. I've tried debugging; I need a fresh pair of eyes to see what I've done wrong.
Here's the form data:
And I've tried using jQuery's AJAX ($.get) too:
$.post('', {username:'test', password:'test'})
.fail(console.error)
.done(() => console.log('Success'));
Edit: After trying multer's app.use(require('multer')().array()); and app.use(require('multer')().none()); middleware, I'm still at the same old issue, except with multer req.body is now undefined instead of {}. This is due to the data being sent as application/x-www-form-urlencoded instead of what I previously thought was application/form-data. As that is the case, the body-parser middleware method should work. If contributing, please do not contribute an answer relating to parsing application/form-data!
Edit 2: For those asking for the session.js code, here it is:
const enmap = require('enmap'),
sessions = new enmap('sessions');
module.exports = (req, res, next) => {
if (!req.cookies) next();
const { cookies: { session: sessionID } } = req;
if (sessionID) {
const session = sessions.get(sessionID);
if (session) {
req.session = session;
} else {
req.session = undefined;
};
} else {
req.session = undefined;
};
next();
};
I'm attaching the whole source code as you people claim to be able to reproduce it somehow. Download it at https://dropfile.nl/get/F7KF (DM me on Discord if it isn't working - PiggyPlex#9993).
For the specific case you're talking about, you usually need only 'body-parser' module to be able to access the form input fields. The minimum example that I advice you to build above it is the following:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({extended : true}));
app.use(bodyParser.json());
app.get('/login', (req, res) => { /* ... */ });
app.post('/login', (req, res) => {
console.log(req.body);
// ...
});
app.listen(3000);
So my advice is to narrow on the cause of the problem by removing any other middleware except for the bodyParser. Try to comment them one-by-one and then you will be able to find the guilty!
Also note that no need to bother yourself trying to make it work with Ajax as it will make no difference. Keep it simple and just try the normal browser submission.
When you found the problematic middleware, debug it. If it's made by you, make sure that you don't make any changes to the req.body. If it a thirdparty middleware, so please consult their installation steps very carefully and I'm happy for further explanation and support
Edit: Some other hints
Make sure that the request is being submitted with the header Content-Type: application/x-www-form-urlencoded
Check if there any CORS problems
File upload middleware to be on a separate path just like the assets
Removing enctype="multipart/form-data" from the form elements works for me, also after registering these middlewares:
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
Sometimes the main point this doesn't work is - when your data passed in the body is in text format, or as in my case in the headers I had 'Content-Type': 'application/x-www-form-urlencoded', but your req.body is expecting JSON data - so please make sure to double-check the 'Content-Type':'application/json' is set on the request headers.
You need to use other module to deal with multipart/form-data
https://github.com/pillarjs/multiparty
app.post('/login', function (req, res) {
const form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
console.log(fields);
});
})
Please use body parser to get the input from the form
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({extended : true}));
app.use(bodyParser.json());
app.post('/anyRoute', (req, res) => {
console.log(req.body); //your input value
});
app.listen(3000);
I had this same error and what fixed it was by removing enctype="multipart/form-data" from the form element. If you are not sending a file alongside the form with the enctype attribute, then you get such errors
I am learning web development and in that, AJAX. For this particular example I am using the XMLHttpRequest object on the browser and Node with Express as my server.
I have a simple HTML form that needs to post data to a Node server. I know that data is being posted successfully, because, I can see the Form Data in the chrome's Network tab.
I have a couple of problems with my code and I've looked for answers on Stackoverflow and also looked at the MDN documentation for the past three days, but am unable to figure this.
The questions below are with respect to the posted code:
If submitForm() returns true, I have the data posted twice to the server, once with an empty request body and once with the expected data. Why?
Post Data when submitForm() returns true
If submitForm() returns false, no data is posted back to the server. Why?
Post Data when submitForm() returns false
If there is no call to submitForm() at all (ie. sans a call to XHR), then the form data is posted correctly and this is seen in the req.body on the server side.
Result of POST when there is no onSubmit event attached to the form
If I set the RequestHeader on xhr to application/x-www-form-urlencoded, this is what I get.
How do I get the form to post data to the server using XMLHTTPRequest?
I am completely lost and am not sure what I am missing. If someone can throw some light, I would appreciate that greatly.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge, chrome=1"/>
<script>
"use strict";
function submitForm()
{
var formElement = document.getElementById("myForm");
var formData = new FormData(formElement);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/Test", true);
xhr.send(formData);
//return false;
}
</script>
</head>
<body>
<form id="myForm" method="POST" action="/Test" onsubmit="return submitForm();" >
<input type="text" value="John" name="name"/>
<input type="submit" value="Send Data"/>
</form>
</body>
</html>
//Server side code (NodeJS)
var express = require('express');
var bodyparser = require('body-parser');
var app = express();
app.use(express.static('./'));
var urlencoded = bodyparser.urlencoded({extended:true});
app.get('/Test', function(req, res){
res.sendFile(__dirname+'/Test.html');
});
app.post('/Test', urlencoded, function(req, res){
console.log("In POST");
console.log(req.body);
res.sendFile(__dirname+'/Test.html');
});
app.listen(8080);
console.log('Now listening on port 8080...');
after looking through your code and testing it out myself. I found out that...
To answer the first question, you are actually submitting the data "John" twice. The first time was through your "submitForm()" function. The second time was through the element attributes method="POST", action="/Test".
The submitForm function is actually working but you are using XMLHttpRequest() to send the post request to the server. If you read the documentation, XMLHttpRequest uses multipart/form-data enctype to send the form data. Therefore your route must be able to handle multipart/form-data format.
To find out if your submitForm() function is indeed called, you could always add a alert(' into the function. If it is called, a prompt will pop up. Always a great way to debug!
Format sent by XMLHttpRequest(): multipart/form-data, format handled: urlencoded, a bit of a mismatch here
Finally let's get to the solution. Like I said your route needs to be able to handle multipart/form-data.
var express = require('express');// I have no idea why I couldn't format this line to code :/
var bodyparser = require('body-parser');
var multer = require('multer') // Use this module to add a middleware onto your route
var mult_handler = multer() // creates a handler object
var app = express();
app.use(express.static('./'));
var urlencoded = bodyparser.urlencoded({extended:true});
app.get('/Test', function(req, res){
res.sendFile(__dirname+'/Test.html');
});
app.post('/Test', mult_handler.none(), function(req, res){
console.log("In POST");
console.log(req.body);
res.sendFile(__dirname+'/Test.html');
});
app.listen(8080);
console.log('Now listening on port 8080...');
I am trying to write a login page . i got the html page with the login box
im enter email and password than submit to server , on server i got route who get the data check on db if doc exists , if its exists should redirect to main page
the problem is the data i send from form to server always undefined i check here on other ppl questions and i didnt find any good result for this
html login page :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/css/style.css" />
<title>{{PageTitle}}</title>
</head>
<body>
{{> header}}
<div class="login-box">
<div class="form">
<form action="/get_user" method="post" class="login-form">
<input type="email" name="Email" placeholder="Email"/>
<input type="password" name="Password" placeholder="Password"/>
<button type="submit">login</button>
</form>
</div>
</div>
{{> footer}}
</body>
server code :
const _ = require('lodash');
const express = require('express');
const bodyParser = require('body-parser');
const {mongoose} = require('./db/mongoose');
const hbs = require('hbs');
var {User} = require('./models/user');
var app = express();
app.set('view engine', 'hbs');
const port = process.env.PORT;
hbs.registerPartials(__dirname + '/../views/partials');
app.user(bodyParser.json());
app.use(express.static(__dirname + '/../public'));
app.use(express.static(__dirname + '/../public/images'));
app.use(express.static(__dirname + '/../public/fonts'));
app.listen(port, () => {
console.log(`Started on port ${port}`);
});
app.get('/', (req, res) => {
res.render('login.hbs', {
PageTitle: 'Log In',
ConnectUser: 'Guest'
});
});
app.post('/get_user', (req, res) => {
var body = _.pick(req.body, ['Email , 'Password']);
User.findOne({
Email: body.Email,
Password: body.Password
}).then((user) => {
console.log(body.Email + ' ' + body.Password);
if(!user) {
return res.status(404).send();
}
var fullName = user.First_Name + ' ' + user.Last_Name;
res.redirect('/mainPage', {ConnectUser: fullName});
}).catch((e) => {
res.status(400).send();
});
});
i did few checks and when i call /get_user req.body->var body -> user r empty
the data arnt pass from form to server im also check this route on postman and its work find when i write the body by myself the only problem i can think is the data i send from form arnt send as json and the body parser send only in json format so maybe i need to change the line
app.use(bodyParser.json());
if any 1 can put in the right direction ill appraise that ty.
When using an html form with method post, the data is posted to the server withContent-Type: application/x-www-form-urlencoded instead of JSON.
Json bodyparser will not do anything with that, as its not using JSON format to send the data. See MDN guide under post method.
In your server code, below app.use(bodyParser.json()) add the following:
app.use(bodyParser.urlencoded({extended: true}));
This will add the data onto the request body the way you expect.
Try playing with the form enc-type attribute and see how to configure the bodyparser to get the values you need based on the enc-type.
application/x-www-form-urlencoded
multipart/form-data
https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype
I have deployed a Parse server on AWS. I intend to host an admin page where we can view some stats and Post some data. Since The parse is a NodeJS application I tried sending a Post request from an HTML form like below.
<form action="/abc" method="post" >
However when we submit form the parameters are not passed in the below post method which is written in the index.js file.
app.post('/abc', function (req, res) {
}
My suggestion would be to use the parse js sdk to get your data. Building and processing forms is doable, but parse has a great client side library that will help you build a secure ui, why not use it?
But to answer your question directly, which is really an express question, not a parse question:
const bodyParser = require('body-parser');
// application/x-www-form-urlencoded which is what a browser will
// send when a form is posted.
app.use(bodyParser.urlencoded({ extended: false }))
app.get('/abc', (req, res) => {
const s = '<form action="/abc" method="post" >'
+ '<input name="say" value="hello" />'
+ '<button>Send it!</button>'
+ '</form>';
res.send(s);
});
app.post('/abc', (req, res) => {
console.log(req.body);
res.send('ok');
});