I'm trying to learn XMLHttpRequests. I'm trying to send some input to the server, but when it gets there, the Object is empty, like {}
That setRequestHeader I commented out, if it's in, the object gets printed out properly, but I get an error that it should be open on the browser. BUT if I put it after the open() statement, it stops working again and the object arrives empty. I also have tried all of that and also JSON.stringfy the variable before sending it but it also didn't work.
//server.js
const express = require('express');
const app = express();
const cors =require('cors')
app.use(cors())
app.use(express.urlencoded({extended:true}))
app.post('/frases', function(req, res) {
console.log(req.body);
const frase = new phrase(req.body);
// console.log(frase);
})
app.listen(3000, () => console.log('listening on 3000...'));
//script.js
var form = document.getElementsByTagName('form')[0];
const xhr = new XMLHttpRequest();
// xhr.setRequestHeader('Content-Type', 'application/json');
form.onsubmit = (e) => {
e.preventDefault();
const thisName = form.elements[0].name;
const thisValue = form.elements[0].value;
const frase = {[thisName]:thisValue};
console.log(frase)
xhr.open('POST', 'http://localhost:3000/frases');
xhr.send(frase);
};
<!-- index.html -->
<form action = "http://localhost:3000/frases" method="post">
<label for="frasefavorita"> Qual é a sua frase favorita?
<input id= 'frase' type="text" name="frasefavorita">
<button id= 'send-frase' type="submit">Enviar</button>
</form>
req.body is empty by default because the body of the incoming request is not read by default. You need middleware that matches the incoming content-type in order to read that body, parse it and put the results into req.body.
And, in your xhr call, you have to decide what content-type you're going to use to send the data, have to put the data into that content-type and you have to set that header appropriately. Then, you will be able to add the right middleware to your server to read and parse that body and then, and only then, can you access it in req.body on your server.
If you were going to send it as JSON, then you can do this on the client to set the content-type for JSON and to format the data as JSON:
form.onsubmit = (e) => {
e.preventDefault();
const thisName = form.elements[0].name;
const thisValue = form.elements[0].value;
const frase = {[thisName]:thisValue};
const xhr = new XMLHttpRequest();
xhr.setRequestHeader("Content-Type", "application/json");
xhr.open('POST', 'http://localhost:3000/frases');
xhr.send(JSON.stringify(frase));
};
Then, on your server, you can add this middleware before your /frases route handler:
// read and parse incoming JSON request bodies
app.use(express.json());
That will read and parse the application/json content-type data coming from your Ajax call.
P.S. I would suggest you use the fetch() interface for writing new code, not the XMLHttpRequest API. fetch() is just much easier to use and a more modern design (using promises).
Try to set the header after you call the open function
xhr.open('POST', 'http://localhost:3000/frases');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(frase);
Related
I'm working on an OAuth2 Discord login to my game's index. I try to pull nickname to my client-side and my Discord bot directly change logged user's nickname to his game name. I have nickname on my PHP-based server-side with JSON data but I don't know how can I pull it to my client-side
Example PHP Code
$myobj->username = "Test";
$myJSON = json_encode($myobj);
echo $myJSON;```
And my Javascript code:
const express = require('express');
const Discord = require('discord.js');
const client = new Discord.Client();
const app = express();
const passport = require("passport");
const { Strategy } = require("passport-discord");
const session = require("express-session");
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(async(user, done) => {
await (await client.guilds.cache.get("guildID").members.fetch(user.id)).roles.add("roleID")
await (await client.guilds.cache.get("guildID").members.fetch(user.id)).setNickname(PHP DATA TO HERE)
return done(null, user)
});
You can do it via AJAX as Lajos suggested, also you can assign it to the JS variable from PHP at the moment of page rendering. All depends on your needs, so just choose the solution which is better for your case.
In your current code instead of echoing JSON, assign it to the JS variable.
echo "<script>let myJsonInJs = $myJson</script>";
so later you can use that variable somehow in your JS, i.e.:
<script>
console.log(myJsonInJs)
</script>
You will need to send an AJAX (Asynchronous Javascript And XML) request to your server-side. Let's implement a function for this purpose:
function sendRequest(type, url, callback, async, params) {
if (async !== false) async = true;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = callback;
xhttp.open(type, url, async);
xhttp.setRequestHeader(\"Content-type\", \"application/x-www-form-urlencoded\");
xhttp.send(params);
}
You can call it like:
sendRequest("POST", "yoururl", function() {
if (this.readyState === 4) {
console.log(JSON.parse(this.responseText));
}
}, true, "username=Test");
Change yoururl to the proper location of your PHP script and pass some parameters if needed.
EDIT
If you are inside the NodeJS environment and you are able to send the request at this level, then you can use fetch, as Endless has pointed out in the comment section.
I just want to extract an http-Post but I didn't get it working. Can somebody help me please? The request is made by my HTML Frontend using XMLHttpRequest() and the backend is node.js. When I send the request I only get an empty Object {}
Node Backend
var express = require('express');
const bodyParser = require('body-parser');
var app = express();
app.use(express.json());
app.post('/save_options', (req, res) => {
console.log(req.body);
res.sendStatus(200);
});
Frontend
let DATA_FRONTEND_OPTIONS = {
"test":"1"
}
function save_options_to_database() {
var do_it_async = true;
var request = new XMLHttpRequest();
request.onload = function () {
var status = request.status;
var data = request.responseText;
}
request.open("POST", "/save_options", do_it_async);
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
//request.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
request.send(JSON.stringify(DATA_FRONTEND_OPTIONS));
}
Simply add
app.use(express.urlencoded());
to your express configuration.
Here is great explanation:
https://stackoverflow.com/a/51844327/8522881
You have to add express.json() and express.urlencoded() for POST request.
Example:
app.use(express.json());
app.use(express.urlencoded());
Because in POST request the data which is sending is in form of some type of data object and you have to tell the server to accept or store that type of data (object), which is enclosed in the body of your POST request.
Above the same solution applied for PUT requests also.
I am trying to do some ajax calls with vanilla JS.
In the back-end I am working with node in the express-framework.
It seems that the data I want to send never actually reaches my back-end. Has anyone an idea what is going on?
My Javascript:
<form id='ajax_form' method='POST' action='/admin/new/tag'>
<input type='text' name='tag' id="tag">
<button type='submit'>Create new tag</button>
</form>
<script>
var ajaxForm = document.querySelector("#ajax_form").addEventListener("submit", function(e){
e.preventDefault();
var form = e.target;
var data = new FormData(form);
var request = new XMLHttpRequest();
request.onreadystatechange = function(){
if(request.response){
[...]
}
}
request.open(form.method, form.action)
request.send(data);
});
</script>
When I iterate over the data object, everything seems to be as it should, returning the keys and values I want to submit through the form.
This is my back-end set-up:
var express = require("express"),
app = express(),
mysql = require("mysql"),
bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({extended: true}));
app.post('/admin/new/tag', function(req, res){
var tag = {tag_name: req.body.tag};
var q = 'INSERT INTO tags SET ?';
connection.query(q, tag, function(error, results, fields){
if (error) throw error;
res.send('succeed');
});
});
When I console.log(req.body.tag), I just get Undefined and req.body is just an empty object.
My database also throws an error as the key tag_name should not be NULL.
When I look at the network panel I receive 503 service unavailable.
Thank you for your response and input!
On server-side you muse use multer for handling multipart/form-data.
Alternatively, you can send the data in JSON format to the server like this way:
var xhr = new XMLHttpRequest();
var data = {
param1: 'value1',
param2: 'value2'
};
xhr.open('POST', '/query');
xhr.onload = function(data) {
console.log('loaded', this.responseText);
};
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
Server-side set the bodyParser to JSON
app.use( bodyParser.json() );
And now you should be able to read the values through the req.body.. syntax.
I'm using protobufs for serializing my data. So far I serialized my data on the server (node restify) send it, receive it (Request is made by XMLHttpRequest) and serialize it on the Client.
Now I want to employ zipping to reduce the transfered file size. I tried using the library pako, which uses zlib.
In a basic script that I used to compare the protobuf and zipping performance to json I used it this way, and there were no problems
var buffer = proto.encode(data,'MyType'); // Own library on top of protobufs
var output = pako.deflate(buffer);
var unpacked = pako.inflate(output);
var decoded = proto.decode(buffer,'MyType');
However if I try to do this in a client-server model I can't get it working.
Server:
server.get('/data', function (req, res) {
const data = getMyData();
const buffer = proto.encode(data, 'MyType');
res.setHeader('content-type', 'application/octet-stream;');
res.setHeader('Content-Encoding', 'gzip;');
return res.send(200,buffer);
});
My own protolibrary serializes the data in protobuf and then deflates it:
...
let buffer = type.encode(message).finish();
buffer = pako.deflate(buffer);
return buffer;
The request looks like this:
public getData(){
return new Promise((resolve,reject) => {
const request = new XMLHttpRequest();
request.open("GET", this.url, true);
request.responseType = "arraybuffer";
request.onload = function(evt) {
const arr = new Uint8Array(request.response);
const payload = proto.decode(request.response ,'MyType')
resolve(payload);
};
request.send();
});
}
The proto.decode method first inflates the buffer buffer = pako.inflate(buffer); and then deserializes it from Protobuf.
If the request is made i get following error: "Uncaught incorrect header check" returned by the inflate method of pako:
function inflate(input, options) {
var inflator = new Inflate(options);
inflator.push(input, true);
// That will never happens, if you don't cheat with options :)
if (inflator.err) { throw inflator.msg || msg[inflator.err]; }
return inflator.result;
}
Also I looked at the request in Postman and found following:
The deflated response looks like this: 120,156,60,221,119,64,21,237,119,39,240,247,246,242,10,49,191,244,178,73,54,157 and has a length of 378564
The same request without deflating (the protobuf) looks like this
�:�:
(� 0�8#H
(� 0�8#H
� (�0�8#�Hand has a length of 272613.
I'm assuming, that I'm doing something incorrectly on the server side, since the inflated request is larger than the one not using compression.
Is it the content-type Header? I'm out of ideas.
Is it possible to POST data from a client javascript page to a node server (server.js) using an AJAX XMLHttpRequest()? What I am looking for is javascript code that will receive the data on the node server, specifically the values for member_nm ("newName") and member_email ("mail#google.com"). I control the server. I also understand that I can also use GET to send the text values by means of a querystring. Below is the request that is sent from the client javascript page by means of an event handler:
document.getElementById("btnAddMember").addEventListener("click", function()
{
var request = new XMLHttpRequest();
var path = "/Users/Admin/WebstormProjects/projectName/server.js";
request.onreadystatechange = function()
{
if ( request.readyState === 4 && request.status == 200 )
{
request.setRequestHeader("Content-Type", "text/plain; charset=UTF-8");
request.open("POST", path, true);
request.send("member_nm=newName&member_email=mail#google.com");
}
};
});
You need to setup your server to accept this post request, the easiest will be to use Express with bodyParser middleware, like this :
var express = require('express');
var server=express();
var bodyParser= require('body-parser');
server.use(bodyParser.json());
server.post('/', function(req, res){
if(req.body){
// get the params from req.body.paramName
}
});
server.listen(8222, function(){
console.log('listening for requests ..')
});
In your client code change the 'path' to point to the server url:port, and I will put these outside of the onReadyStateChange:
request.setRequestHeader("Content-Type", "text/plain; charset=UTF-8");
request.open("POST", path, true);
request.send("member_nm=newName&member_email=mail#google.com");
This is a working solution on how to POST variables from a client javascript file to a Node server using Express. The POST is initiated on the client by means of an event handler, btnAddMember. txtName.value and txtMembershipType.value contain the values to be posted. Note the syntax that is necessary to parse the values correctly. member_nm and member_type will be used to reference the properties on the Node server. First the client javascript:
document.getElementById("btnAddMember").addEventListener("click", function()
{
var request = new XMLHttpRequest();
var path = "http://0.0.0.0:0000"; // enter your server ip and port number
request.open("POST", path, true); // true = asynchronous
request.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
var text= '{"member_nm":"' + txtName.value + '","member_type":"' + txtMembershipType.value + '"}';
request.send ( text );
});
Next is the server side code. Note that bodyParser must now be added to your project as a node_module. This can be done through the node program manager (npm). The POST statement basically parses the req.body from a JSON format to a javascript object format using a variable called 'member'. The code then logs the posted values for the two variables, member_nm and member_type. Finally a response status is sent to the client if the POST is successful.
var bodyParser = require("body-parser");
...
app.use(bodyParser.text({ type: "application/json" }));
...
// receive the POST from the client javascript file
app.post("/", function (req, res)
{
if (req.body)
{
var member = JSON.parse( req.body ); // parse req.body as an object
console.log("member_nm: " + member.member_nm );
console.log("member_type: " + member.member_type );
res.sendStatus(200); // success status
}
else
{
res.sendStatus(400); // error status
}
});