Hook into XMLHttpRequest open and send method - javascript

I am using the following code to hook into XMLHttpRequest open/send methods:
var lastParams = '';
var send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(data){
lastParams = data;
send.call(this, data);
};
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, uri, async, user, pass) {
this.addEventListener("readystatechange", function(event) {
if(this.readyState == 4){
var self = this;
var response = {
method: method,
uri: uri,
params: lastParams,
responseText: self.responseText
};
console.log(response);
}
}, false);
open.call(this, method, uri, async, user, pass);
};
It is working fine in the case of single ajax request at a time.
When multiple ajax request are firing at a time, then lastParams can contain wrong data (means lastParams can contain data from other ajax request). I want to uniquely associate the lastParams with request's other attributes?
Is there any id attribute in XMLHttpRequest so that I can uniquely identify the ajax request instance?
Thanks in advance.

Have a look at https://github.com/jpillora/xhook and the demos
//modify 'responseText' of 'example2.txt'
xhook.after(function(request, response) {
if(request.url.match(/example\.txt$/)) {
response.text = response.text.replace(/[aeiou]/g,'z');
}
});

For uniquely associating some data with specified XMLHttpRequest instance you can simply add property into XMLHttpRequest instance and save data into property. For example:
// generating data for request
var data=generateData();
// sending data
var xhr=new XMLHttpRequest();
xhr.open("POST","/yourpage.php",true);
xhr.onreadystatechange=function(event){
if(this.readyState===4){
console.log(this.mySendedData);
}
};
/** if you need to preserve 'data' variable value for each xhr **/
xhr.mySendedData=data;
/***************************************************************/
xhr.send(data);

why not make 'lastParams' as an array, and you always push data, instead of overwriting it everytime.

Related

is there a way to easily check if the image url is valid or not?

I'm trying to write a function that checks if the image URL is an actual image, if it is it will return true, or else it will return false,
something like that:
checkImage(imageURL){
if imageURL.isReal{
return true
}
return false
}
I have found alot of answers but they didnt really work as boolean functions
The most elegant solution is using a XMLHttpRequest and check the response code.
If it's 200, the image exists, if it's something different it's highly possible that the picture - or more precise the url in general - doesn't exist.
Here's an example:
function checkImage(url) {
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.send();
request.onload = function() {
status = request.status;
if (request.status == 200) //if(statusText == OK)
{
console.log("image exists");
} else {
console.log("image doesn't exist");
}
}
}
checkImage("https://picsum.photos/200/300");
Well, as I said this is more a general approach.
If you want to be sure that it's actually an image, you can utilize the Image object's onerror and onload events.
function checkImage(url) {
var image = new Image();
image.onload = function() {
if (this.width > 0) {
console.log("image exists");
}
}
image.onerror = function() {
console.log("image doesn't exist");
}
image.src = url;
}
checkImage("https://picsum.photos/200/300");
You could possibly use the fetch API. A modern variant of XHR.
So like
async function checkImage(url){
const res = await fetch(url);
const buff = await res.blob();
return buff.type.startsWith('image/')
}
By this
checkImage('https://example.com/notAnImage.txt') // false
checkImage('https://example.com/image.png') // true
You could use getResponseHeader of XMLHttpRequest to check the mime type of the successfully returned content of your request. In fact you can't know the content of the response only based upon the http success response code of your request.
The XMLHttpRequest method getResponseHeader() returns the string
containing the text of a particular header's value. If there are
multiple response headers with the same name, then their values are
returned as a single concatenated string, where each value is
separated from the previous one by a pair of comma and space. The
getResponseHeader() method returns the value as a UTF byte sequence.
In this example, a request is created and sent, and a readystatechange
handler is established to look for the readyState to indicate that the
headers have been received; when that is the case, the value of the
Content-Type header is fetched. If the Content-Type isn't the desired
value, the XMLHttpRequest is canceled by calling abort().
var client = new XMLHttpRequest();
client.open("GET", "unicorns-are-teh-awesome.txt", true);
client.send();
client.onreadystatechange = function() {
if(this.readyState == this.HEADERS_RECEIVED) {
var contentType = client.getResponseHeader("Content-Type");
if (contentType != my_expected_type) {
client.abort();
}
}
}
All the best.

Bad request error when calling a custom action through Javascript

I created a custom action on CRM 365 which has one input parameter of type entity reference and it refers to the user entity, I tried to change the input parameter into another type and it works well. So I think the issue is in the way I pass the entity reference value, I tried to change it but I haven't had any luck so can someone tell me what is the wrong in the below code?
function CreateBlockHistory() {
var Id = Xrm.Page.data.entity.getId();
Id = Id.replace("{", "").replace("}", "");
var data = {
"BlockedBy": {
"ohd_blockedby": Xrm.Page.context.getUserId().replace("}", "").replace("{", ""),
"#odata.type": "Microsoft.Dynamics.CRM.systemuser"
}
};
var serverURL = window.parent.Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest();
req.open("POST", serverURL + "/api/data/v8.1/new_units(" + Id + ")/Microsoft.Dynamics.CRM.ohd_ActionTest", false);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.onreadystatechange = function () {
if (this.readyState == 4 /* request completed */) {
req.onreadystatechange = null;
if (this.status == 200 /* response ready */) {
var data = JSON.parse(this.response);
}
else {
var error = JSON.parse(this.response).error;
}
}
};
req.send(window.JSON.stringify(data));
}
To start with 400 Bad request - it is a very generic useless error, instead of relying on this - try to run the same snippet in browser console or CRM REST Builder by passing hardcoded guid parameters to see execution status. You can debug too
I see your XMLHttpRequest is running synchronous ( bool param as false), switch it to Async & see
Also I see you are getting Xrm context with mixed approach like window.parent sometimes & directly sometimes. window.JSON too. If this is executing in web resource not in any entity form then fix it appropriately
You can register a plugin on that custom action message, profile/debug & see for any clue

Is there a way to get params from a XMLHttpRequest response?

Say I'm interested in checking the params that were sent with the XMLHttpRequest.
For instance, if I sent a POST petition with param 'option=1' can I retrieve that from the response?
I checked for the methods and properties but haven't seen a way to get it.
Fire a XMLHTTPRequest and examine the response object in your browser's JS console (F12 for Chrome/Firefox).
I believe the data is not there, at least I once changed the XMLHttpRequest open() method for a project (of course, I might have been just too stupid to find it). That way, my default error handler knows the original URL when printing errors to the user/sending errors to the error reporting backend.
Rough code snippet, pulled from a projects init-code:
/**
* Check XMLHttpRequest availability
*/
var ajax = null;
var proto = null;
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest ();
proto = XMLHttpRequest.prototype;
} else if (window.ActiveXObject) {
try {
ajax = new ActiveXObject("Msxml2.XMLHTTP.6.0");
proto = ActiveXObject("Msxml2.XMLHTTP.6.0").prototype;
} catch (e) { }
}
if (ajax == null) {
alert ("Can not create AJAX object. You need a more recent browser!");
return;
}
/**
* Update ajax prototype to store the URL (for better error handling)
*/
try {
var origOpen = proto.open;
proto.open = function (method, url) {
this._url = url;
return origOpen.apply (this, arguments);
}
} catch (e) {
console.log ("Can not patch XMLHttpRequest to store URL. Console output will omit them...");
}
You would need to adapt this for POST data passed to the send() function instead. Be aware, that the method is probably bad style, and my JS style might be even worse!
Better: But you could always pass the POST data directly to the callback function, without storing it in the XMLHTTPRequest object:
var postData = "SomeStuff-Foobar123";
var ajax = new XMLHttpRequest (); //add magic for other browsers here
ajax.open ("POST", "ajax.php", true);
ajax.onreadystatechange = function () {
if (this.readyState != 4 || this.status != 200) {
console.log ("Not ready, yet...");
return 0;
}
//response is in this.responseText
//but you can still access the parent objects!
console.log ("Done with Code 200. POSTed data: " + postData);
}
ajax.send (postData);
As Bergi said it's not possible to retrieve the parameters that were sent with the request on the response. So I'm closing the question.
Thanks to everyone who helped!

Any way to make AJAX calls to Gmail API without going through JS library?

A simple guide to making a GET request to get a user's messages through Gmail API can be found here.
But the way we are instructed to do the request is in the following manner:
function getMessage(userId, messageId, callback) {
var request = gapi.client.gmail.users.messages.get({
'userId': userId,
'id': messageId
});
request.execute(callback);
}
Is it possible to make the request using the good ol' XMLHttpRequest object on the client side? If so what parameters should be passed into the call?
I have tried this:
var getMessages = function() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200)
console.log(xhr.responseText);
}
xhr.open( "GET", "https://www.googleapis.com/gmail/v1/users/me/messages", true );
xhr.send();
}
But I get a 401, even after authenticating.
As it states in this answer, you should pass the access token as a query parameter with the name access_token, or prefix the authorization header value with "Bearer", like so:
xhr.setRequestHeader("authorization", "Bearer " + userToken.access_token);

Setting server response data to a variable to work with

Hey guys I am using a executePostHttpRequest function that looks exactly like the code posted below. Currently when I run the function I get a server response with the appropriate data but I am not sure how I can work with the response data? how do I store it in to a variable to work with?
Javascript executePostHttpRequest
function executePostHttpRequest(url, toSend, async) {
console.log("====== POST request content ======");
console.log(toSend);
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
xmlhttp.open("POST", url, async);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.setRequestHeader("Content-length", toSend.length);
xmlhttp.send(toSend);
console.log("====== Sent POST request ======");
}
Here is what I am doing to execute it. Using Javascript
var searchCriteria = JSON.stringify({
displayName : search_term
});
console.log("Search: "+searchCriteria) //Search: {"name":"John, Doe"}
var response = executePostHttpRequest("/web/search", searchCriteria, true);
console.log(response) //undefined
So currently the console.log for response shows undefined. But if I take a look at the network tab on Chrome Dev Tools and look at the /web/search call I see a JSON string that came back that looks something like this.
[{"id":"1","email":"john.doe#dm.com","name":"John, Doe"}]
I'd like to be able to display the data from this response to a HTML page by doing something like this.
$("#id").html(response.id);
$("#name").html(response.name);
$("#email").html(response.email);
I tried taking another route and using Jquery POST instead by doing something like this.
var searchCriteria = JSON.stringify({
displayName : search_term
});
console.log("Search: "+searchCriteria) //Search: {"name":"John, Doe"}
$.post("/web/search", {
sendValue : searchCriteria
}, function(data) {
$.each(data, function(i, d) {
console.log(d.name);
});
}, 'json').error(function() {
alert("There was an error searching users! Please contact administrator.");
});
But for some reason when this runs I get the "There was an error" with no response from the server.
Could someone assist me with this? Thank you for taking your time to read it.
Your executePostHttpRequest function doesn't do anything with the data it's receiving. You would have to add an event listener to the XMLHttpRequest to get it:
function getPostData(url, toSend, async, method) {
// Create new request
var xhr = new XMLHttpRequest()
// Set parameters
xhr.open('POST', url, async)
// Add event listener
xhr.onreadystatechange = function () {
// Check if finished
if (xhr.readyState == 4 && xhr.status == 200) {
// Do something with data
method(xhr.responseText);
}
}
}
I've added the method parameter for you to add a function as parameter.
Here's an example of what you were trying to do:
function displayStuff(jsonString) {
// Parse JSON string
var data = JSON.parse(jsonString)
// Loop over data
for (var i = 0; i < data.length; i++) {
// Get element
var element = data[i]
// Do something with its attributes
console.log(element.id)
console.log(element.name)
}
}
getPostData('/web/search', searchCriteria, true, displayStuff)

Categories