In javascript XMLHttpRequest, changing POST request to GET request - javascript

My javascript library is sending payload data from client browser to web server.
And, intermittently, I find a weird situation in Web server logs.
When sending data from the client through my library, using the POST method of XHR and the GET method is sent intermittently with the same target URL.
My library code is as follows...
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function (event) {
if (xhr.readyState === 4 /** responseText is not available yet */) {
const statusCode = xhr.status
const responseText = xhr.responseText
if (responseValidator(statusCode, responseText)) {
if (successCallback) successCallback(xhr)
} else {
const error = new Error(`${ErrorType.INVALID_RESPONSE}: ${statusCode}`)
Logger.error(error)
handleServerError(payloads)
if (failureCallback) failureCallback(error)
}
}
}
xhr.open('POST', url, true /** async */)
xhr.setRequestHeader('Content-Type', 'text/plain; charset=utf8')
xhr.withCredentials = true
xhr.timeout = timeoutMillis
xhr.ontimeout = function (event) {
const error = new Error(`${ErrorType.REQUEST_TIMEOUT} (${timeoutMillis} millis)`)
Logger.error(error)
if (failureCallback) failureCallback(error)
}
xhr.onerror = function (e) {
handleServerError(payloads)
}
xhr.send(JSON.stringify(payloads))
Why is this happening?

Related

Querying the API via JavaScript / CORS (teamup.com calendar)

I am currently trying to figure out how to query the API of a calendar on teamup.com and retrieve data (events in the calendar) from it.
There's a code example on their website: Querying the API via JavaScript / CORS
I tried to make it work in Visual Studio, so I had to install XMLHttpRequest via npm and add a require code line:
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// Creates a CORS request in a cross-browser manner
function createCORSRequest(method, url) {
var apiKey = 'API_KEY'; //placeholder for api key
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari/IE10+.
xhr.open(method, url, true);
xhr.setRequestHeader('Teamup-Token', apiKey);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE8/IE9.
xhr = new XDomainRequest();
// XDomainRequest does not support querying HTTPS from HTTP pages
if (window.location.protocol === 'http:') {
url = url.replace('https://', 'http://');
}
if (-1 === ['GET', 'POST'].indexOf(method)) {
alert('XDomainRequest only supports GET and POST methods');
return;
}
if (-1 === url.indexOf('?')) {
url += '?_teamup_token=' + apiKey;
} else {
url += '&_teamup_token=' + apiKey;
}
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
// Sends the actual CORS request.
function makeCorsRequest(url, successCallback, errorCallback) {
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
// Response handlers.
xhr.onload = function (xhr) {
if (xhr.target.status < 400) {
if (successCallback) successCallback(xhr.target);
} else if (errorCallback) {
errorCallback(xhr.target);
}
};
xhr.onerror = function (xhr) {
if (errorCallback) {
errorCallback(xhr.target);
}
};
xhr.send();
}
// Send a GET request for all events in a date range
makeCorsRequest(
'https://api.teamup.com/ks73ad7816e7a61b3a/events?startDate=2015-06-01&endDate=2015-06-05',
function(xhr) {
var data = JSON.parse(xhr.responseText);
alert('Successfully Received: ' + JSON.stringify(data));
},
function(xhr) {
var data = JSON.parse(xhr.responseText);
alert('Request failed with code '+ xhr.status +': ' + JSON.stringify(data));
}
);
When I try to run the program per node I get this terminal output:
PS C:\Users\...\Documents\GitHub\teamup-test> node team-up-test.js
C:\Users\...\Documents\GitHub\teamup-test\team-up-test.js:45
if (xhr.target.status < 400) {
^
TypeError: Cannot read properties of undefined (reading 'target')
at exports.XMLHttpRequest.xhr.onload (C:\Users\...\Documents\GitHub\teamup-test\team-up-test.js:45:17)
at exports.XMLHttpRequest.dispatchEvent (C:\Users\...\Documents\GitHub\teamup-test\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:591:25)
at setState (C:\Users\...\Documents\GitHub\teamup-test\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:614:14)
at IncomingMessage.<anonymous> (C:\Users\...\Documents\GitHub\teamup-test\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:447:13)
at IncomingMessage.emit (node:events:539:35)
at endReadableNT (node:internal/streams/readable:1345:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
So it seems like the program cannot read xhr.target.status, but why?
Summarized: I want to fetch calendar event data from my calendar on team-up per JS and display that data on a discord bot.
I am wondering if I even do need CORS since it's only for browsers. Hoping someone could guide me into the right direction please.
The code tutorial here: https://apidocs.teamup.com/#querying-the-api-via-javascript--cors is to be executed in the browser, in the client. I don't think it can be used in the server. Remember, Node.js is a back-end language, it runs on the server, not on the browser.
You can make an API call in Node.js with the code below, but you should study Axios later
const https = require('https');
const options = {
hostname: 'api.teamup.com',
path: '/ks73ad7816e7a61b3a/events?startDate=2015-06-01&endDate=2015-06-05',
headers: {
"Teamup-Token" : "API_KEY"
},
};
https.get(options, (resp) => {
let data = '';
resp.on('data', (receivedDataBuffer) => {
data += receivedDataBuffer;
});
resp.on('end', () => {
let receivedDataAsJSON = JSON.parse(data);
//do what you need with the json
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});

XMLHttpRequest return from a function before response is back

I have a function as the code below, I am trying to send a file through XMLHttpRequest to the server and then store it in DB and retrieve the id of the file in DB and make an object of ids.
The problem is that the function exits a lot before I got the response back from the server to store it in the object therefore the object doesn't store those values.
I know that I need make the XHR asynchronous but it doesn't change the result, I have also tried timeout or using a different platform like Ajax but still, it didn't work.
async function getFileObj() {
var FileObject = {}
for (let key1 in PObj) {
FileObject[key1] = {}
for (let key2 in PObj[key1]) {
FileObject[key1][key2] = {}
for (let key3 in PObj[key1][key2]) {
const formData = new FormData();
formData.append('myFile.png', filesObjDB[key1][key2][key3]);
var xhr = new XMLHttpRequest();
xhr.open("POST", 'url', true);
xhr.onreadystatechange = async function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200)
var id = await xhr.response.text();
FileObject[key1][key2][key3] = parseInt(id)
}
xhr.responseType = 'blob';
xhr.send(formData);
}
}
}
return FileObject;
}
Help would be very appreciated!
You are not awaiting the request. To make the existing code wait for the result, you'd need to wrap the outdated callback-based code in a promise and await that (and also I don't think getting the response text of an XHR works as you showed, I changed it now):
// This is just to demonstrate what was immediately wrong
// with the existing code - it's not the best solution! See below.
FileObject[key1][key2][key3] = await new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
var id = xhr.responseText;
resolve(parseInt(id));
}
};
xhr.send(formData);
});
Note there is no error handling yet, if the request fails everything will just hang.
But at that point, it doesn't actually make sense to use XHR in the first place! It's a lot more straightforward to use fetch, which has a promise API out of the box:
const response = await fetch(url, { method: 'POST', body: formData })
FileObject[key1][key2][key3] = parseInt(await response.text())

XMLHttpRequest file upload returning a 500 error

I am trying to upload a file using XMLHttpRequest() but the post request is returning a 500 internal server error. I've made sure the file parameter is sending through the file object and that the action URL is correct. Am I missing something?
HTML:
<input type="file" class="form-control" name="documents" (change)="onFileUploadChange($event)">
Component:
onFileUploadChange(_event: any) {
let file = _event.srcElement.files;
let postData: any = null;
this._fileUploadService.uploadFile(this.uploadURL, file);
}
Service:
uploadFile(_url:string,_file:File):Promise<any> {
return new Promise((resolve, reject) => {
var xhr:XMLHttpRequest = new XMLHttpRequest();
console.log(_file);
console.log(_file[0].name);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// ...
} else if (xhr.status === 500) {
// ...
}
else {
// ...
}
}
};
var formData = new FormData();
formData.append('file', _file[0], _file[0].name);
xhr.open('POST', _url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Content-Type','multipart/form-data');
xhr.send(formData);
});
}
A 500 error means the request got to the destination and there was a problem at the destination. Try checking the destination for errors.
Maybe you send wrong request? Last time I've got the same problem and there was a solution:
Saving Blob as xlsx in Angular2

How to handle XMLHttpRequests in a redux action?

I have a redux-form that is passing props to my action. The property this.props.userImages[0] is an image file from a file input on that form. I'm then taking that image and making and XMLHttpRequest to Cloudinary which generates a url for that image. Once I receive the url data (xhr.responseText), I'd like to then merge it with my other props to that I can then post all of my props to an API (all form info + newly created image URL).
I know that I have to wait for my request to generate a url to resolve, but having issues with getting it right before I can pass it onto my other function which can take that info and merge it in with props before posting to my API.
//..
function generateUrl(props) {
// Grabs image file from my form's file input and uploads
// to cloudinary service so that a URL can be generated
const cloudinaryURL = 'https://api.cloudinary.com/v1_1/<my_name>/image/upload';
const apiKey = 'secret_key';
const uploadPreset = 'test_preset';
const data = new FormData();
data.append('file', props.userImages[0]);
data.append('upload_preset', uploadPreset);
data.append('api_key', apiKey);
const xhr = new XMLHttpRequest();
xhr.open('POST', cloudinaryURL, true);
xhr.send(data);
xhr.onReadyStateChange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
return JSON.parse(xhr.responseText);
}
};
return xhr.onReadyStateChange();
}
export function createReview(props) {
const imageUrl = generateUrl(props);
const mergedProps = //...
// Here I'd like to merge my newly generated
// url back into props before I post to my API like so...
const request = axios.post(`${REQUEST_URL}/api`, mergedProps)
return {
type: CREATE_REVIEW,
payload: request
}
};
Any and all help is greatly appreciated.
This has nothing to do with promises in the context of your example XMLHttpRequest based code.
The assumption your making is that the callback assigned to onReadyStateChange does something with it's return value. Instead anything returned from that function is dutifully ignored.
What you want is to pass the value onward through another callback.
function generateUrl(props, callback) {
// Do things here
xhr.onReadyStateChange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
callback(JSON.parse(xhr.responseText));
}
};
}
generateUrl(props, (response) => {
const mergedProps = // Use response as expected.
});
Since you mentioned promise and your using ES2015 we can convert this to actually use promises which is probably what you wanted to begin with.
function generateUrl(props) {
return new Promise((resolve, reject) => {
const cloudinaryURL = 'https://api.cloudinary.com/v1_1/<my_name>/image/upload';
const apiKey = 'secret_key';
const uploadPreset = 'test_preset';
const data = new FormData();
data.append('file', props.userImages[0]);
data.append('upload_preset', uploadPreset);
data.append('api_key', apiKey);
const xhr = new XMLHttpRequest();
xhr.onReadyStateChange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve(xhr.responseText);
} else {
reject(new Error(`Failed HTTP request (${xhr.status})`));
}
};
xhr.onerror = reject;
xhr.open('POST', cloudinaryURL, true);
xhr.send(data);
});
}
generateUrl(props)
.then(JSON.parse)
.then(results => {
// Do something with response
})
.catch(error => {
// Do something with the error
});

Ajax - Function to check if url exists before send request

I am writing a function to grab a json file from a website/server and save it in local storage with the code:
function donators() {
var jsonURL = "http://mywebsite.com/donators.json";
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonURL, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
localDataStore.set("fb_donators", xhr.responseText);
}
};
xhr.send();
}
The above code works perfectly fine when the json file can be reached, but if my server goes down and the file cannot be reached my script halts at the line with xhr.send() with the error:
GET http://mywebsite.com/donators.json net::ERR_NAME_NOT_RESOLVED
Is there a way I can detect check if url can be reached before the send request to stop the send the request and allow the rest of my script to continue to run instead of getting halted at xhr.send()?
Thanks!
You can use a try block for this. It still requires the HTTP request, but it will fail gracefully and you can handle the error any way you'd like.
function donators() {
var jsonURL = "http://mywebsite.com/donators.json";
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonURL, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
localDataStore.set("fb_donators", xhr.responseText);
}
};
xhr.timeout = 5000;
xhr.ontimeout = function() {
alert( 'The operation timed out.' );
}
try { xhr.send(); } catch( err ) {
alert( 'Error getting data: ' + err.message );
}
}

Categories