I want to build a login page for my web app and I want to send data to my express server using fetch but when I log the req to the console the "req.body" is an empty object even if I sent an object with name and password properties can anyone help
client_side code:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input type="text" id="name" name="name" />
<input type="password" id="password" name="password" />
<button onclick="send()">login</button>
<script>
async function send() {
let name = document.getElementById('name').value
let password =
document.getElementById('password').value
let res = await
fetch('http://localhost:3000/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
password
})
})
if(res.redirected) {
window.location.href = "/chat"
localStorage.setItem('name', name)
localStorage.setItem('password', password)
} else {
alert('not correct :P')
}
}
</script>
</body>
</html>
server_side code:
app.use(express.urlencoded({ extended: true }));
app.post('/api/login', (req, res) => {
console.log(req.body)
// why the output is an empty object {}
res.redirect('/login')
})
I am a frontend dev and am new to backend
#edit: my server code was app.post() but I accidentally put app.get() #because I rewrite the server code not paste it
First, change app.get to app.post to handle the post request.
Second, add the built-in JSON body parser to properly add the "body" property to the request object. app.use(express.json())
To more robustly handle authentication, use passportjs.
Try app.post instead of app.get. See https://expressjs.com/en/guide/routing.html
Your javascript is performing an HTTP POST request, but express is only handling an HTTP GET request.
Try to install and use body-parser
Change app.get() to app.post(). But it will be right to use .put() if you processing /login path.
Related
I tried to post the form with Javascript fetch API, but it doesn't work. Where am I making mistakes?
the HTML form :
<form id="my-form" method="post" action="/" enctype="multipart/form-data">
<input type="text" name="name" id="ok">
<input type="text" name="pro" id="okpro">
<button type="submit"> Submit it </button>
</form>
Javascript codes I wrote in it :
const form = document.getElementById('my-form');
form.onsubmit = async function(e){
e.preventDefault()
const formData = new FormData(form)
for (const it of formData) {
console.log(it[0], it[1]);
}
const response = await fetch('/', {method: 'POST', body: formData})
const result = await response.json()
console.log(result);
}
note: I tried with form.addEventListener also, nothing changes :(
and the post route from nodeJs :
route.post("/", (req, res) => { console.log("Our Body", req.body)
res.status(200).json({
res: req.body, }) })
If you try to use/parse req.body, I highly recommend to use a package like body-parser.
Here's an example configuration:
const bodyParser = require("body-parser");
//some code, e.g. imports or other use() calls
app.use(
bodyParser.urlencoded({
extended: false,
}),
); //for form actions, e.g. posting directly
app.use(bodyParser.json()) //for normal requests like in your example
//Routes
Then, your req.body should have data. Make sure to include the .use() function above your existing requests.
Here is a link to body-parser on npm: https://npmjs.com/body-parser
As you seem to only be submitting text, you can remove the enctype from your form.
Hope it helps :)
I was trying to use the Fetch API POST method in Vanilla JS. The endpoint was located in Node-JS code.
The POST method function run whenever ONKEYDOWN function runs on html text input. Whenever we type on keyboard, it sends data to the Node-JS Endpoint and then prints it. Each time I typed, the data was being sent but was only received only 6 times before it stopped printing the req.body.
Here's is my code for HTML + Vanilla JS (index.html).
<div onkeydown="post()">
First Name
<input type="text" name="FirstName" id="FirstName">
<br> <br>
Middle Name
<input type="text" name="MiddleName" id="MiddleName">
<br> <br>
Last Name
<input type="text" name="LastName" id="LastName">
</div>
<script>
function post() {
const formData = {
FirstName: document.getElementById('FirstName').value,
MiddleName: document.getElementById('MiddleName').value,
LastName: document.getElementById('LastName').value,
}
localStorage.setItem("FirstName", formData.FirstName)
localStorage.setItem("MiddleName", formData.MiddleName)
localStorage.setItem("LastName", formData.LastName)
console.log(formData);
fetch('/', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData)
})
}
</script>
Here's is my Code for Node-js (index.js)
const express = require('express')
const app = express()
app.use(express.json({ limit: '20mb'}))
app.use(express.static('/')) //static folder
app.listen(80, () => {
console.log('THE PORT IS UP AND RUNNING')
})
app.get('/', (req, res) => {
res.sendFile('index.html', { root: __dirname })
})
let i = 0; // to display the number of outputs
app.post('/', (req, res) => {
console.log(req.body, i++)
// print the data
})
According to this code, I recieve the req.body only for 6 times which is printed in the terminal (6 times). Please help
You need to send response to previous requests.
The easiest way to achieve it is to call .end() method of the res object
// print the data
res.end();
Your requests don't hit the server due to browser's concurrent requests limit which is 6 for some browsers including Google Chrome. Browser waits for pending requests to finish before sending next ones, but your server never sends response.
I'm trying to send an AJAX POST request for a login page using javascript via Node.js however I don't really know how to do it. Sorry that I'm really new to this. Here's my code:
In HTML:
<form>
<label for="email"><b>Email Address</b></label><br>
<input type="text" name="email"><br>
<label for="password"><b>Password</b></label><br>
<input type="text" name="password"><br><br>
<input type="submit" class = "button" value="Login" onclick= "submitlogin()">
</form>
In JS:
function submitlogin(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if(this.readyState ==4 && this.status == 200){
console.log("success");
} else if (this.readyState == 4 && this.status == 401) {
console.log("Failed");
}
};
xhttp.open("POST","/login",true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(JSON.stringify({ email: this.email, password: this.password }));
}
Route:
var user = [{
EmailAddress: 'anne#gmail.com',
Password: 'first'
}]
router.post('/login', function(req, res, next) {
if((req.body.email === user[0].EmailAddress) && user[0].Password === req.body.password){
res.status(200).send();
} else {
res.status(401).send();
}
});
What should go into xhttp.send()? What am I doing wrongly? Can anyone help me with this? (preferably just javascript not jQuery) Thank you!
This is a typical issue about how to deal with the info passed to server using a way that you didn't expected.
There's a lot of things to improve in your code, but i won't focus on this right now. So, first of all, if you pay attention to what happens in your browser right after the submit button is clicked, on the URL you can see the typed inputs in querystring format. And it isn't referencing the /login route descripted.
Something like:
http://localhost:3000/?email=marcelobraga%40hotmail.com&password=agoodpassword
It happened because the Form element, by default, uses the parameters to communicate with your server. Not the object "Body" that you're expecting to receive through the HTTP Request object.
If you really want to access the login data passed as URL parameters, you will need just to fix your code in your front and backend to pass correctly object and prepare your server to read it on the right place.
I strongly advise you not to use the form html element this way. Either use the XMLHttpRequest. I suggest to use the Axios to do deal with the HTTP requests and send Body informations to avoid explicit such a sensitive information like logins could be. Other reason to use Axios is for easy syntax and clean code.
See how i made it with axios:
In HTML (I will insert all the HTML to you see the importation the Axios Lib tag):
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!-- importing axios to this document -->
<title>Document</title>
</head>
<body>
<label for="email"><b>Email Address</b></label><br>
<input type="text" id="email" name="email"><br>
<label for="password"><b>Password</b></label><br>
<input type="text" id="password" name="password"><br><br>
<input type="submit" class="button" value="Login" onclick="submitlogin()">
</body>
</html>
In JS file:
const emailInput = document.getElementById("email").value //getting the value from input typed
const passwordInput = document.getElementById("password").value //getting the value from input typed
axios.post('/login',
{
email: emailInput,
password: passwordInput
}
)};
In expressjs:
const express = require("express")
const app = express();
const path = require('path');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post('/login', (req, res) => {
console.log(req.body); //console to verify the body data received on this endpoint request
const user = [{
EmailAddress: 'anne#gmail.com',
Password: 'first'
}];
if((req.body.email === user[0].EmailAddress) && user[0].Password === req.body.password){
res.status(200).send("Success");
console.log("Success");
} else {
res.status(401).send("Wrong email or password");
console.log("Wrong email or password");
}
});
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Conclusion
The way that you was doing this made the data unreachable on the backend. The backend was expecting to receive the information to proceed with the verifications on the Body data of the Request. And you was passing it as a query parameter.
You can pass information using params or query params to the backend, but the login information must be more protected. Sending it in your body avoid people to find this data lookin in your history, for example. It's not the most secure way, because someone can catch this data on the middle. But, anyway, is something you should know.
I hope i could help you.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a HTML form as follows:
<form id="loginForm" name="loginForm">
<div class="form-group">
<input type="username" class="form-control" id="username" name="username" placeholder="Your username..." >
</div>
<div class="form-group">
<input type="password" class="form-control" id="password" name="password" placeholder="Your password...">
</div>
<button class="btn btn-primary btn-block btn-round" id="loginButton" type="submit">Login</button>
</form>
and a Javascript file containing the following code to make an AJAX request:
//credits to #lndgalante
if (typeof window !== 'undefined') {
window.addEventListener('load', () => {
const form = document.getElementById('loginForm');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const elements = event.target;
const username = elements.username.value;
const password = elements.password.value;
const dataToSend = { username, password };
try {
console.log(JSON.stringify(dataToSend)); //To check variables are being passed correctly
return await fetch('/login', {
method: 'POST',
body: JSON.stringify(dataToSend),
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
console.log(error);
}
});
});
};
and a node.js file with the corresponding POST route:
app.post('/login', async (req, res) => {
try {
const username = req.body.username;
const password = req.body.password;
console.log(username, password, req.body); //To check variables are being passed correctly
...
}
});
But the problem is,
console.log(JSON.stringify(dataToSend)); returns {"username":"username1","password":"password1"} //or whatever the user input is as expected, whereas
console.log(username, password, req.body) returns undefined undefined {}.
Does anyone know what I'm doing wrong?
Edit: I am using const app = express(); and I have app.use(bodyParser.urlencoded({ extended: true })); in my node.js file.
You must use a body parser, otherwise your NodeJS application will not know how to interpret your string received in the request body.
npm install --save body-parser
and
var bodyParser = require('body-parser')
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
or
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart());
So your code will run propperly.
More details here: How to retrieve POST query parameters?
Assuming you're using Express.js (you should probably tag the question) you need to make sure you use the express.json() (or bodyParser.json()) middleware for JSON body parsing.
const app = express();
app.use(express.json());
app.post('/login', ...);
Your client-side code is correct.
I have app.use(bodyParser.urlencoded({ extended: true })); in my node.js file.
You're POSTing JSON, not URL Encoded data.
You need a JSON parser.
app.use(bodyParser.json());
… or to post URL Encoded data:
I've found docs teaching on how to implement Twilio on server-side using Node, however, I couldn't find an end-end example where I can send a SMS coming from my client app.
Can anyone tell me what the implementation would look like to send a post custom SMS from client to server?
Disclaimer my server file is named as app.js and my client file is named as index.js
**1- This is what I have currently setup on my app.js
const express = require('express');
const app = express();
const path = require('path');
const twilio = require('twilio');
const bodyParser = require('body-parser');
//JSON DATA
const guests= require('./public/data/Guests');
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static('public'));
//SET PORT
app.set("port", process.env.PORT || 3000);
//GET JSON DATA
app.get('/data', function(req, res) {
Promise.all([guests])//combine requests into one object
.then(([guests]) => {
res.send({guests});
});
});
//CATCHALL
app.get("/*", function(req,res){
let file = req.params[0] || "/views/index.html";
res.sendFile(path.join(__dirname, "/public/", file));
});
//LISTEN ON PORT
app.listen(app.get("port"), function(){
console.log("Listening on port: " , app.get("port"));
});
let client = new twilio('xxxxxxxxxx', 'xxxxxxxxxxxxx');
app.post('/sms', (request, result) => {
const message = request.body.message;
client.messages.create({
to: +1847820802492359,
from: +8475302725792530 ,
body: message
}).then(() => {
// message sent successfully, redirect to the home page.
res.redirect('/');
}).catch((err) => {
console.error(err);
res.sendStatus(400);
});
});
-2 am trying to process a dynamic message in my index.js. The code works on the DOM properly, it is just the SMS with Twilio that isn't posting the message to the server
$(function() {
$.ajax({
type: "GET",
url: "/data",
success: res => {
//console.log(res);
handleMessage(res);
},
error: err => console.log(err)
});
//message method
let handleMessage = (res) => {
const getFirstName = res.guests.map(name => name.firstName);
//populate drop-down select
let handleSelect = () => {
//adds first names to select dropDown
$.each(getFirstName, function(i, value) {
$('#selectName').append($('<option>').text(value).attr('value', value));
});
};
handleSelect();
let handleSubmit = () => {
$("#form").submit(function(e) {
e.preventDefault();
let name = $('#selectName').val();
let greetGuest = `Welcome ${name}!`;
console.log(greetGuest);
//append to Dom
$('.showMessage').append(`<div class="newMessage"><span>${greetGuest}</span></div>`);
});
};
handleSubmit()
};
});
-3 HTML form
<form id="form" action="/sms" method="POST">
<label>
<label for=selectName>Guest
<select id="selectName" class="select " name="sms">
</select>
</label>
</label>
<input type="submit" value="send" class="btn btn-success" />
</form>
Am I having an asynchronicity issue here?
Twilio developer evangelist here.
I can give you a basic example here, which should give you a good idea of how to achieve this. I'll start with the server side, which you already have the basics of.
Firstly, I would recommend you use a POST request rather than a GET, simply because GETs can be easily repeated by users or cached by proxies. I assume you are using Express as the web application server. You will also need the body-parser module to read the data that we send from the client side.
const Twilio = require('twilio');
const express = require('express');
const bodyParser = require('body-parser');
const app = new express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static('public'));
const twilio = new Twilio(YOUR_ACCOUNT_SID, YOUR_AUTH_TOKEN);
app.post('/messages', (request, result) => {
const message = request.body.message;
twilio.messages.create({
to: TO_NUMBER,
from: FROM_NUMBER,
body: message
}).then(() => {
// message sent successfully, redirect to the home page.
res.redirect('/');
}).catch((err) => {
console.error(err);
res.sendStatus(400);
});
});
app.listen(3000);
This sets up a server which is serving static files from a public directory and then has one endpoint, POST to /messages, that sends a message.
We now need to create the client side. I shall do this in HTML only for simplicity. You need a form that will POST to the /messages endpoint with, in this case, a single field for the message. I've included a textarea to write the message in and a button to submit the form. If you save this as index.html in the public directory where you run the application from then it should work.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Send a message!</title>
</head>
<body>
<h1>Send a message!</h1>
<form action="/messages" method="POST">
<label for="message">What would you like to send?</label>
<textarea name="message" id="message"></textarea>
<button type="submit">Send!</button>
</form>
</body>
</html>
Let me know if that helps at all.
Update
So you're looking to make the request to the server using Ajax so your page doesn't reload and you can display a different message. Your current form seems to have removed the message textarea that I added, I'll put it back in again. I assume you also want to send the message to whichever guest you are welcoming at the time, but I don't know how that works in your system, so I'm going to avoid that for now and hopefully you can sort it out.
So, if you update your form to something like this:
<form id="form" action="/sms" method="POST">
<label>
<label for=selectName>Guest
<select id="selectName" class="select " name="sms">
</select>
</label>
</label>
<label for="message">Message</label>
<textarea id="message" name="message"></textarea>
<input type="submit" value="send" class="btn btn-success" />
</form>
Then you need to add to your JavaScript a way to actually submit the form (since you are preventing the submission with e.preventDefault().
const $form = $('#form');
$form.submit(function(e) {
e.preventDefault();
let name = $('#selectName').val();
let greetGuest = `Welcome ${name}!`;
console.log(greetGuest);
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: $form.serialize(),
success: function(data) {
console.log("The message has been sent");
},
error: function() {
console.error("The message couldn't be sent");
console.error(...arguments);
}
})
//append to Dom
$('.showMessage').append(
`<div class="newMessage"><span>${greetGuest}</span></div>`
);
});
In this case we are hooking into the callback for the submit event to make a new $.ajax request to the form's action, using the method (POST), and including the form data (which we get from $form.serialize()). We then setup success and error callbacks as you've done at the top of the function.
Let me know if this helps.