This question already has answers here:
Pass Data to Service in Axios
(1 answer)
axios post request from frontend not recieving in node js backend
(3 answers)
Closed 18 days ago.
I'm using classic Javascript ajax to send a request with a payload to my backend (node.js). On the backend, I get the request but I'm not finding the payload in the request. I need help with this (please).
Here's the ajax call:
function signIn() {
const username = document.getElementById('username');
const password = document.getElementById('password');
ajax('auth/signin', 'POST', {username: username.value, password: password.value});
}
function ajax(endpoint, method, payload) {
const xhttp = new XMLHttpRequest();
const url = 'http://localhost:3000/' + endpoint;
xhttp.onreadystatechange = function() {
console.log('readyState: ', this.readyState);
if (this.readyState === 4) {
if (this.status === 200) {
console.log('success!');
} else {
console.log('error: ', JSON.stringify(this));
}
}
};
xhttp.open(method, url, true);
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
if (payload) {
xhttp.send(payload);
} else {
xhttp.send();
}
}
On the backend, I print out the request like this:
router.post('/signin', (req, res, next) => {
console.log('signing in');
fs.appendFileSync('log.txt', new Date().toString() + ': in auth.js : router.post/signin\n' + util.inspect(req, {depth: 7}));
});
This writes the request 7 layers deep to log.txt. I open log.txt, I see the request in all its gory detail, but when I do a search for the username or password I entered, I find nothing.
So either the payload (username/password) is not getting to the backend with the request, or it's more than 7 layers deep. I'm assuming it's the former, not the latter.
Is there anything wrong with how I'm making my ajax call? Is this not how you send a payload along with a request? Is it something else I'm doing wrong? Thanks!
Related
I'm new to Express and trying to create a login authentication system. But I'm having issues getting XHR to show a ready state 4. It was working fine until I added express.Router which I saw in a GitHub project.
These are my relevant bits of code:
// server.js
const userAuth = require("./auth");
app.use(cors());
app.use(bodyParser.json());
app.use("/auth", userAuth);
// ./auth/index.js
const router = require("express").Router();
const userLogin = require("./userLogin");
const userRegister = require("./userRegister");
router.post("/login", userLogin);
router.post("/register", userRegister);
module.exports = router;
// ./auth/userLogin.js
module.exports = (req, res) => {
const { username, password } = req.body;
console.log(username, password);
res.status(200).send("hello");
};
// client side
const http = new XMLHttpRequest();
http.open("post", "https://example.com/auth/login");
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = () => {
if (!(http.readyState === 4 && http.status === 200)) {
console.error("Could not submit form.");
console.log(http.responseText);
}
};
http.send(JSON.stringify({ username, password }));
The chrome console shows "State 2", then "State 3" plus the "hello" response. But there is no "State 4"?
The code is pretty much identical to the linked Github project (theirs have async in userLogin.js but I've tried that too).
Any help/tips much appreciated!
change your onreadystatechange method to this and it will work:
http.onreadystatechange = function () {
// rest of your code
}
This is a template you can refer back to if needed:
const http = new XMLHttpRequest();
http.open("post", "https://example.com/auth/login");
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function () { // change this line
if (http.readyState === 4 && http.status === 200) {
console.log(http.responseText);
}
else {
console.error("Error in submitting or receiving response.");
}
};
http.send(JSON.stringify({ username, password }));
if this answer helps solving the issue, consider accepting the answer or upvoting it. Thank you.
When I send a GET req from my client to my Express server it sends the data to the client but I get an XMLHttpRequest ready state of 1 and a status of 0 and it never logs the response text.
Client:
req.onreadystatechange = function() {
console.log(this.readyState);
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
req.open('GET', url + 'users', true);
req.send();
Server:
app.get('/users', function(req, res) {
res.send(users);
});
If anyone can tell me why I can't receive the array of users on client side and how to fix it. That would be great.
First I would use fetch javascript because it looks more natural.
/* on server */
app.get('/users', function(req, res) {
res.send(users);
});
/* on client */
fetch('/users').then(async (response) => {
if (response.status === 200) {
console.log(await response.text());
// do you receive something ?
}
else {
throw new Error('something unexpected occurred');
}
}.catch(err => { console.err(err) })
If you don't receive anything, then you should check if your front page is served from the same data-providing server because when you call for /users the browser is prepending the host to the path. So if both your client page and your back server is not running on the same host it will fail.
Im having trouble sending form data to my local NodeJS express server. I believe it has something to do with how I'm formatting my request. I am trying to register a new user account to a Postgresql database, using Passport as middleware, although I dont believe the code ever makes it that far.
Chrome DevTools Network Tab gives me additional info about the bad request
{"status":"Cannot read property 'length' of undefined"}
When a user hits 'Create Account', this code is fired off:
processForm(event) {
// prevent default action. in this case, action is the form submission event
event.preventDefault();
// create a string for an HTTP body message
const name = encodeURIComponent(this.state.user.name);
const email = encodeURIComponent(this.state.user.email);
const password = encodeURIComponent(this.state.user.password);
const formData = `name=${name}&email=${email}&password=${password}`;
// create an AJAX request
const xhr = new XMLHttpRequest();
xhr.open('post', '/auth/register');
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.responseType = 'json';
xhr.addEventListener('load', () => {
if (xhr.status === 200) {
// success
// change the component-container state
this.setState({
errors: {}
});
// set a message
localStorage.setItem('successMessage', xhr.response.message);
this.setState({redirect: true});
} else {
// failure
const errors = xhr.response.errors ? xhr.response.errors : {};
errors.summary = xhr.response.message;
this.setState({
errors
});
}
});
xhr.send(formData);
}
Chrome DevTools flashes the 'xhr.send(formData)' as the first error in the stack.
This is the express handler code, but I don't think it ever makes it that far:
router.post('/register', authHelpers.loginRedirect, (req, res, next)
=> {
return authHelpers.createUser(req, res)
.then((response) => {
passport.authenticate('local', (err, user, info) => {
if (user) { handleResponse(res, 200, 'success'); }
})(req, res, next);
})
.catch((err) => { handleResponse(res, 500, 'error'); });
});
Any help would be greatly appreciated. I've spent hours trying to troubleshoot it. That's like every stackoverflow post ever.
How do I get the request headers in Azure functions ? I use JavaScript http trigger to handle a request. I need to read some token sent in the request header from the front end. How can I do this ?
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (true) {
context.log(req.headers['Authorization'])
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello there "
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
context.done();
};
Use req.headers, e.g.
module.exports = function (context, req) {
context.log('Header: ' + req.headers['user-agent']);
context.done();
};
You can also do something like this with the run time context also.
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.log(context.req.headers.authorization)//You can get the pass tokens here
context.done();
};
In case anyone wants the C#:
e.g.
To get the Authorization token:
log.Info(req.Headers.Authorization.Token.ToString());
More on the various headers here.
I have an Express server running.
What i do is upload an Excel File from HTML and then Express parse that file and do some calculating.
In the Excel file, each row has information about address of a User.
For each Address, our Express server will use google map geocoding API to calculate the latitude & longitude.
But, because Google doesn't accept more than 50 request per second to their geocoding API, so i have to use settimeout to delay the calculating.
For example if the Excel file has 50 addresses, so i have to use settimeout on each address to avoid that rate limit.
Here is my code to use settimeout and calculate latitude, longitude
createFromFile(req, res) {
var form = new formidable.IncomingForm();
return form.parse(req, function (err, fields, files) {
if (err)
return res.status(500).json({error: err.message})
var workbook = new exceljs.Workbook();
return workbook.xlsx.readFile(files.excelfile.path).then(function() {
// use workbook
var worksheet = workbook.getWorksheet(1)
var data = []
for (var i=2; i<=worksheet.rowCount; i++) {
data.push({
from_name: worksheet.getCell('A'+i).value + '',
from_address: worksheet.getCell('B'+i).value + '',
from_phone: worksheet.getCell('C'+i).value + '',
receiver_name: worksheet.getCell('D'+i).value + '',
receiver_address: worksheet.getCell('E'+i).value + '',
receiver_phone: worksheet.getCell('F'+i).value + '',
note: worksheet.getCell('H'+i).value + ''
})
}
var delay = function(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t)
})
}
return Promise.all(data.map(function(item, i) {
return function() {
return delay(750*i).then(function() {
winston.log('debug', 'process for item '+i)
return geocoder.geocode(item.from_address).then(function(geo_data) {
data[i].from_coord = {
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
}
return geocoder.geocode(item.receiver_address).then(function(geo_data) {
data[i].receiver_coord = {
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
}
})
})
.catch(function(geo_error) {
winston.log('error', 'geo_error', {error: geo_error})
throw new Error('Address in line ' + i + ' is not valid')
})
})
}()
}))
.then(function() {
winston.log('debug', 'we are done calculating location')
return res.status(201).json(data)
})
})
.catch(function(e) {
winston.log('error', 'an error occurred')
return res.status(500).json({error: e.message})
})
})
}
And below is my codes to call that Express API, i used React to do frontend job & used javascript fetch api to request to server.
startUploadFile() {
this.props.showLoader()
let data = new FormData()
data.append('excelfile', this.state.selectedFile)
data.append('name', 'excelfile')
var me = this
fetch(Const.restServer + '/create-from-file', {
headers: {
'Access-Token': this.props.access_token,
},
method: 'POST',
body: data
})
.then(function(r) {
return r.json()
})
.then(function(r) {
if (r.hasOwnProperty('error'))
throw new Error(r.error)
me.props.hideLoader()
me.props.showDialog('success', 'Process Complete')
})
.catch(function(e) {
console.log(e)
me.props.hideLoader()
me.props.showDialog('error', e.message)
})
}
My problem is when i used above codes to uploading a file on browser, i see two request in express log file. Something like this:
I will provide my codes to log info of every request here too
app.use(function(req, res, next) {
winston.log('debug', 'call api:', {
api: req.url, requestMethod: req.method
})
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Access-Token, Web-Admin-Request"
);
next()
});
function isAuthenticated(req, res, next) {
/**
** Rest API Middleware check if access_token is valid
*/
let accessToken = req.body.accessToken || req.get('Access-Token')
// bunch of codes to check accessToken
next()
}
app.post('/order/create-from-file', isAuthenticated, orderController.createFromFile);
I don't understand why this happen. If I use Postman & select a File & upload, it works fine - just only One Request in logs.
Can anyone tell me what is the reason. I feel like this is a Bug of Express. My Express version is 4.15.2
The Access-Token request header your code adds to the request triggers browsers to send a CORS preflight OPTIONS request before trying the POST request.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests gives more detail but the gist of it is, as long as your code’s adding that Access-Token header to the request, there’s no way you can prevent browsers from making the extra preflight OPTIONS request—because it’s something browsers do automatically as part of the CORS protocol.
The reason you don’t see the extra request when you use Postman is that it doesn’t do the CORS preflight OPTIONS request—only browsers send it, and only for requests made by XHR/Fetch from frontend JavaScript code running in a browser at a specific origin (which Postman isn’t).
Well, finally i can fix this problem by passing 'Access-Token' into request body instead of request header (now, my server always receive only one request). Thank to #sideshowbarker because your comment trigger me to do this method.
I still think this Problem is a bug in Express, but because it didn't occur on my local development environment, so i will not send a report to them.