AJAX: Posts are sent empty - javascript

I am using AJAX for the first time and try to send data to my PHP controller with an XMLHttpRequest. Unfortunately, the data arrives empty there.
request.onload = () => {
let responseObject = null;
try {
responseObject = JSON.parse(request.responseText);
} catch (e) {
console.error('Could not parse JSON!');
}
if (responseObject) {
handleResponse(responseObject);
}
};
const requestData = `title=${this._title.value}&reference=${this._reference.value}&area=${this._area.value}`;
request.open('post', 'checknews');
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
request.send(requestData);
Whats wrong ?

Related

Outer function being called before xmlhttprequest being done

room.onPlayerChat is an outer event i have no control on it, When i try to use it i need to process something on message and checking player role through xmlhttprequest and wait for response then send message to room chat but it doesn't wait for it(xmlhttprequest) to return the player's role and send the normal message (normal player role), how to hang that outer event (room.onPlayerChat) and its needed to handle any room chat source.
const makeRequest = (method, url, data = {}) => {
const xhr = new XMLHttpRequest();
return new Promise(resolve => {
xhr.open(method, url, true);
xhr.onload = () => resolve({
status: xhr.status,
response: xhr.responseText
});
xhr.onerror = () => resolve({
status: xhr.status,
response: xhr.responseText
});
if (method != 'GET') xhr.setRequestHeader('Content-Type', 'application/json');
data != {} ? xhr.send(JSON.stringify(data)) : xhr.send();
})
}
room.onPlayerChat = async function (player,message) {
let request = await makeRequest("GET", 'URL/TO/CHECK/PLAYER/ADMIN/ROLE' + player.name);
if (request.response == "YES")
{
room.sendmessage("ADMIN" + player.name + message);
return false;
}
}

How to pass internal function values as parameters to its callback

Im sorry I don't know the exact wording so please bear with me. what Im trying to do is the same thing as we all do with the event listeners like so:
foo.addEventListener('click', function(event) {
console.log(event.target)
})
with the example above I can access the event instance using the anonymous callback function. in my case, I have this simple function:
function post_rqst({ url, data = '', callback }) {
let request = new XMLHttpRequest();
request.open("POST", url, true);
request.onload = function() {
callback()
}
request.send(data)
}
now when I call the post_rqst(), I want to be able to access the request instance inside the callback definition like so:
post_rqst({
url: 'foo.com/bar/',
data: '[x,y,z]',
callback: function(request) {
if (request.status === 200) {
console.log('done!')
}
}
})
Im a javascript newbie and I don't know what I don't know. thank you for your guidance in advance.
You can just pass that request instance when you call callback, so instead of:
function post_rqst({ url, data = '', callback }) {
let request = new XMLHttpRequest();
request.open("POST", url, true);
request.onload = function() {
callback();
};
request.send(data);
}
You would have:
function post_rqst({ url, data = '', callback }) {
let request = new XMLHttpRequest();
request.open("POST", url, true);
request.onload = function() {
callback(request);
};
request.send(data);
}
Here you can see that in action using setTimeout to fake that request:
function fakePost({ url, data = '', callback }) {
const request = { url, data, method: 'POST' };
setTimeout(() => {
callback(request);
}, 1000);
}
fakePost({
url: 'https://stackoverflow.com/',
data: 'foobar',
origin: 'https://stackoverflow.com/',
callback: (req) => {
console.log('Callback received req =', req);
},
});

Postman post request works but ajax post does not. Have checked client side js over and over

first question ever on stackoverflow and boy do I need an answer. My problem is that I have an endpoint to create an item, and it works when I send a POST request with Postman. I'm using node and express:
router.post("/", jwtAuth, (req, res) => {
console.log(req.body);
const requiredFields = ["date", "time", "task", "notes"];
requiredFields.forEach(field => {
if (!(field in req.body)) {
const message = `Missing \`${field}\` in request body`;
console.error(message);
return res.status(400).send(message);
}
});
Task.create({
userId: req.user.id,
date: req.body.date,
time: req.body.time,
task: req.body.task,
notes: req.body.notes
})
.then(task => res.status(201).json(task.serialize()))
.catch(err => {
console.error(err);
res.status(500).json({ message: "Internal server error" });
});
});
That endpoint works when I send with Postman and the req body logged with the right values.
But when I send my ajax request, my server code logs the req.body as an empty object ('{}'). Because Postman works I believe the problem is with my client side javascript but I just cannot find the problem. I and others have looked over it a million times but just can't find the problem. Here is my client side javascript:
//User submits a new task after timer has run
function handleTaskSubmit() {
$(".submit-task").click(event => {
console.log("test");
const date = $(".new-task-date").text();
const taskTime = $(".new-task-time").text();
const task = $(".popup-title").text();
const notes = $("#task-notes").val();
$(".task-notes-form").submit(event => {
event.preventDefault();
postNewTask(date, taskTime, task, notes);
});
});
}
function postNewTask(date, taskTime, task, notes) {
const data = JSON.stringify({
date: date,
time: taskTime,
task: task,
notes: notes
});
//Here I log all the data. The data object and all its key are defined
console.log(data);
console.log(date);
console.log(taskTime);
console.log(task);
console.log(notes);
const token = localStorage.getItem("token");
const settings = {
url: "http://localhost:8080/tasks",
type: "POST",
dataType: "json",
data: data,
contentType: "application/json, charset=utf-8",
headers: {
Authorization: `Bearer ${token}`
},
success: function() {
console.log("Now we are cooking with gas");
},
error: function(err) {
console.log(err);
}
};
$.ajax(settings);
}
handleTaskSubmit();
What I would do:
Change header 'application/json' to 'application/x-www-form-urlencoded' since official docs have no info on former one.
Stop using $.ajax and get comfortable with XHR requests, since jquery from CDN is sometimes a mess when CDN get's laggy and XHR is a native implement and available immediately. Yes it's a code mess, but you always know that it is not the inner library logic thing, but your own problem. You blindly use library, that conceals XHR inside and you do not know how to ask the right question "XHR post method docs" because you are not yet comfortable with basic technology underneath.
Save this and import the variable
var httpClient = {
get: function( url, data, callback ) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
var readyState = xhr.readyState;
if (readyState == 4) {
callback(xhr);
}
};
var queryString = '';
if (typeof data === 'object') {
for (var propertyName in data) {
queryString += (queryString.length === 0 ? '' : '&') + propertyName + '=' + encodeURIComponent(data[propertyName]);
}
}
if (queryString.length !== 0) {
url += (url.indexOf('?') === -1 ? '?' : '&') + queryString;
}
xhr.open('GET', url, true);
xhr.withCredentials = true;
xhr.send(null);
},
post: function(url, data, callback ) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
var readyState = xhr.readyState;
if (readyState == 4) {
callback(xhr);
}
};
var queryString='';
if (typeof data === 'object') {
for (var propertyName in data) {
queryString += (queryString.length === 0 ? '' : '&') + propertyName + '=' + encodeURIComponent(data[propertyName]);
}
} else {
queryString=data
}
xhr.open('POST', url, true);
xhr.withCredentials = true;
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(queryString);
}
};
usage is as simple as jquery: httpClient.post(Url, data, (xhr) => {})
Check if you have body parser set-up in app.js
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // get information from html forms
app.use(bodyParser.urlencoded({ extended: true })); // get information from html forms
if body parser is set-up try changing header to 'multipart/form-data' or
'text/plain'.
For just the sake check req.query
Cheers! :)

Recover public address from a typed signature

I am implementing an application, on which it is necessary to confirm your Ethereum wallet. In order to do so, I am currently writing a basic HTML and Javascript Web page.
This is my javascript code.
const msgParams = [
{
type: 'uint',
name: 'Please verify your generated key',
value: ''
}
]
var signeddata = ''
function sanitizeData (data) {
const sanitizedData = {}
for (const key in TYPED_MESSAGE_SCHEMA.properties) {
data[key] && (sanitizedData[key] = data[key])
}
return sanitizedData
}
window.onload = function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://plapla.pla/initializeVerification', true);
// If specified, responseType must be empty string or "text"
xhr.responseType = 'json';
xhr.onreadystatechange = function () {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200) {
msgParams[0].value = xhr.response.key;
console.log(msgParams);
}
}
};
console.log('!');
xhr.send(null);
}
function verify() {
let web3 = window.web3;
console.log(web3);
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use the browser's ethereum provider
web3 = new Web3(web3.currentProvider);
console.log(web3);
} else {
console.log('No web3? You should consider trying MetaMask!')
}
//Login tracken
web3.currentProvider.publicConfigStore.on('update', callback => {
console.log(callback);
//Login tracken
});
console.log(web3.eth.accounts);
web3.eth.getCoinbase(function(error, result){
if(!error) {
console.log("params: "+msgParams[0]);
var fromAddress = result;
web3.currentProvider.sendAsync({
method: 'eth_signTypedData',
params: [msgParams, fromAddress],
from: fromAddress,
}, function (err, result) {
if (err) return console.error(err);
if (result.error) {
return console.error(result.error.message)
}
var sign = {};
sign.data =[{
type:msgParams[0].type,
name:msgParams[0].name,
value:msgParams[0].value
}];
sign.sig = result.result
var json = JSON.stringify(sign);
console.log("Do JSON"+json);
var xhr = new XMLHttpRequest();
console.log("Fa: "+fromAddress);
xhr.open('POST', 'https://plapla.pla/addWallet', true);
xhr.setRequestHeader('Content-type','application/json; charset=utf-8');
// If specified, responseType must be empty string or "text"
xhr.responseType = 'text';
xhr.onreadystatechange = function () {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200) {
console.log(xhr.response);
}
}
};
xhr.send(json);
});
}
});
};
I am retrieving a random number from my backend on load and want the User to sign this Code with Metamask. I then send it again to my firebase backend, which receives the data as well as the signature.
Firebase handles it as Follows:
exports.addWallet = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const signed = req.body;
console.log(signed);
const recovered = sigUtil.recoverTypedSignature(signed);
return recovered;
})
});
As you can see, I am using the eth-sig-util library: https://github.com/MetaMask/eth-sig-util
But I always get this error from firebase:
TypeError: Cannot read property 'EIP712Domain' of undefined
at Object.findTypeDependencies (/user_code/node_modules/eth-sig-util/index.js:97:47)
at Object.encodeType (/user_code/node_modules/eth-sig-util/index.js:76:21)
at Object.hashType (/user_code/node_modules/eth-sig-util/index.js:127:30)
at Object.encodeData (/user_code/node_modules/eth-sig-util/index.js:42:33)
at Object.hashStruct (/user_code/node_modules/eth-sig-util/index.js:116:30)
at Object.sign (/user_code/node_modules/eth-sig-util/index.js:153:21)
at Object.recoverTypedSignature (/user_code/node_modules/eth-sig-util/index.js:235:36)
at cors (/user_code/index.js:29:31)
at cors (/user_code/node_modules/cors/lib/index.js:188:7)
at /user_code/node_modules/cors/lib/index.js:224:17
So I figured out, that the problem is with the library... Do I send the wrong parameters to the function? Is there any other way to recover the public address from the signer?
You need to use object data, can check code here:
https://github.com/MetaMask/eth-sig-util/blob/master/index.js#L234
{
data: '', // the data you signed
sig: '' // the r, s, v concated string
}
Or you can use ethereumjs-util to recover the public key if you know the signed data.

415 (Unsupported Media Type) Error

On my MVC project, I have a POST request to a Web API using XmlHttpRequest.
I send an array of documents' routes in a JSON format and expecting to get from the server a Zip file (ArrayBuffer).
self.zipDocs = function (docs, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {//Call a function when the state changes.
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseBody);
}
}
xhr.open("POST", '../API/documents/zip', true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.responseType = "arraybuffer";
console.log(docs);
xhr.send(docs);
var arraybuffer = xhr.response;
var blob = new Blob([arraybuffer], { type: "application/zip" });
saveAs(blob, "example.zip");
}
And my ZipDocs function on the WebAPI (using the DotNetZip library):
[HttpPost]
[Route("documents/zip")]
public HttpResponseMessage ZipDocs([FromBody] string[] docs)
{
using (var zipFile = new ZipFile())
{
zipFile.AddFiles(docs, false, "");
return ZipContentResult(zipFile);
}
}
protected HttpResponseMessage ZipContentResult(ZipFile zipFile)
{
// inspired from http://stackoverflow.com/a/16171977/92756
var pushStreamContent = new PushStreamContent((stream, content, context) =>
{
zipFile.Save(stream);
stream.Close(); // After save we close the stream to signal that we are done writing.
}, "application/zip");
return new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
}
But the response I'm getting from the server is:
POST http://localhost:1234/MyProject/API/documents/zip 415 (Unsupported Media Type)
Why is this happening, and how do I fix it?
Based on this post
You might want to try
xhr.setRequestHeader("Accept", "application/json");
And your code is missing a semicolon on
xhr.setRequestHeader("Content-type", "application/json")
Thanks to #David Duponchel I used the jquery.binarytransport.js library, I sent the data to the API as JSON and got back the Zip File as Binary.
This is my JavaScript ZipDocs function:
self.zipDocs = function (docs, callback) {
$.ajax({
url: "../API/documents/zip",
type: "POST",
contentType: "application/json",
dataType: "binary",
data: docs,
processData: false,
success: function (blob) {
saveAs(blob, "ZippedDocuments.zip");
callback("Success");
},
error: function (data) {
callback("Error");
}
});
}
The API's code remains the same.
That works perfectly.

Categories

Resources