Meteor's recent update added an option to the http package to use beforeSend, allowing us to access the xhr object on the client. I am on occasion uploading or downloading large files on the client and I want to have a progress indicator as well as a cancel option. I can not get beforeSend to work, unfortunately.
Question
What is the proper way to use beforeSend and/or why does my code not work?
What Happens
Http.call runs completely, but my beforeSend function is never executed.
Relevant Packages
Meteor 1.2.1
http 1.1.1
aldeed:http
Relevant Client Code
httpProgress = function(xhr) {
console.log('I never see this');
xhr.onprogress = function(e) {
if (e.lengthComputable) {
setProgress((e.loaded / e.total) * 100, 'downloading...', true);
}
else{
setProgress(-1, 'downloading...', true);
}
};
};
HTTP.call('GET',url, {
beforeSend: httpProgress,
headers: {
'Accept': '*/*'
},
responseType: 'arraybuffer' //using aldeed:http here
}, function(error, result) {
...
}
);
Meteor's Documentation on beforeSend
On the client, this will be called before the request is sent to allow
for more direct manipulation of the underlying XMLHttpRequest object,
which will be passed as the first argument. If the callback returns
false, the request will be not be send.
HTTP.call method in aldeed:http package does not support any beforeSend parameter yet. You can check it in source code here
Related
I am developing React application and for frontend AJAX requests I use jQuery, but I want to cache my requests like angular http.get(url, {cache: true }) does.
Is there any way which can help me do this global caching for GET requests.
I tried to add cache: true property to request but it seems not working.
For example my code looks like this
$.ajax(source, {
method: 'GET',
data: {
c: count,
p: period
},
cache: true,
success: (response) => {
}
})
I have tried also
$.ajaxSetup({
cache:true
});
for all requests, but unfortunatley I can see request under Chrome devtools network tab, as well as in my server logs.
So I want to prevent from doing same request if data and url is same.
I can create some storage myself, but I think there should be default way for doing this.
Thanks in advance!
One approach could be checking if the last request data are the same than the current.
var lastRequestedData = {};
function myAjaxRequest(requestData) {
if (JSON.stringify(requestData) != JSON.stringify(lastRequestedData)) {
lastRequestedData = requestData;
alert('Makes the ajax request: '+ JSON.stringify(requestData));
//$.ajax(...)
}
}
myAjaxRequest({"c":1,"p":2}); // Fire
myAjaxRequest({"c":1,"p":2}); // Not fire
myAjaxRequest({"c":2,"p":3}); // Fire
Question about store data population in isomorphic flux apps. (I'm using react, alt, iso and node but theory applies to other examples)
I have a flux 'store' (http://alt.js.org/docs/stores/) that needs to get data from an api:
getState() {
return {
data : makeHttpRequest(url)
}
}
and as the user navigates through the SPA, more data will be loaded via http requests.
I want this app to be isomorphic so that I can render the apps full html including latest data server side and return it to the user for fast initial page load.
react.renderToString() lets me render the app as html, and I can seed the data using alt&iso like:
storeData = { "MyStore" : {"key" : "value"}}; // set data for store
alt.bootstrap(JSON.stringify(storeData || {})); // seed store with data
var content = React.renderToString(React.createElement(myApp)); // render react app to html
The problem is that I will see errors when running the js server side as the store will want to make a http request which it wont be able to do (as xmlhttprequest wont exist in node)
Whats the best way to solve this problem?
The only solution I can think of would be to wrap the httprequest from the store with:
var ExecutionEnvironment = require('react/lib/ExecutionEnvironment');
...
if (ExecutionEnvironment.canUseDOM) {
// make http request
} else {
// do nothing
}
Any better ideas? Thanks in advance.
I would recommend hooking into your Ajax library or XMLHttpRequest directly if you are running serverside. Just shim it with code that supplies data directly from your database or application.
A quick example:
var noop= function(){}
window.XMLHttpRequest= function(){
console.log("xhr created", arguments);
return {
open: function(method, url){
console.log("xhr open", method, url);
// asynchronously respond
setTimeout(function(){
// pull this data from your database/application
this.responseText= JSON.stringify({
foo: "bar"
});
this.status= 200;
this.statusText= "Marvellous";
if(this.onload){
this.onload();
}
// other libs may implement onreadystatechange
}.bind(this), 1)
},
// receive data here
send: function(data){
console.log("xhr send", data);
},
close: noop,
abort: noop,
setRequestHeader: noop,
overrideMimeType: noop,
getAllResponseHeaders: noop,
getResponseHeader: noop,
};
}
$.ajax({
method: "GET",
url: "foo/bar",
dataType: "json",
success: function(data){
console.log("ajax complete", data);
},
error: function(){
console.log("something failed", arguments);
}
});
http://jsfiddle.net/qs8r8L4f/
I whipped this up in the last 5 minutes mostly using the XMLHTTPRequest mdn page
However if you are using anything not directly based on XMLHttpRequest or explicitly node aware (like superagent) you will probably need to shim the library function itself.
Other work to do on this snippet would be implementing errors and different content types.
This doesn't seem to be working :
$.ajaxSetup({
headers: {
Accept: 'application/vvv.website+json;version=1 ',
Authorization: 'Token token=\"FuHCLyY46\"'
}
});
I would have thought it would. If I add these filters specifically to my AJAX call then they do work. I'd like to do this globally for all AJAX calls.
I did some additional tests and the code you posted works perfectly. If you have problems with something in how the parameters are setup, you could always to go the beforeSend call and modify the xml request yourself.
$.ajaxSetup({
beforeSend: function (xhr)
{
xhr.setRequestHeader("Accept","application/vvv.website+json;version=1");
xhr.setRequestHeader("Authorization","Token token=\"FuHCLyY46\"");
}
});
It's also possible to do this in a framework-agnostic way by monkey-patching the open method:
var o = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(){
var res = o.apply(this, arguments);
var err = new Error();
this.setRequestHeader('X-Ajax-Stack', JSON.stringify(err.stack));
return res;
}
In this example I'm sending stack trace information via a header, which allows the backend to know where Ajax requests originated, even if it's from third-party code that doesn't use jQuery.
(Note: careful about headers getting too big)
The beforeSend answer does not establish the same header's as adding header directly to the ajax call. So in order for jQuery to do this properly I add this :
headers: myGlobalHeaders
where myGlobalHeaders is a global variable. Unfortunately, I have to write this extra line on every single ajax call. Terrible! Maybe I'll edit the jQuery framework to handle this..
EXT JS - I would like to know how to check the json response for a session time out like if a user is idle for say 20 minutes or so if his session is expired or not
There is no standard way of handling session timeouts in ExtJS. ExtJS is a client-side library, used to create the user interface/front-end layer of an application, while session management takes place on the server side.
ExtJS Ajax requests implement a callback mechanism. It means that a certain Javascript function is assigned as the callback function, which is called when the Ajax request has finished (either successfully or unsuccessfully). Here's an example taken from ExtJS API Documentation - see parameters success and failure that define the callback functions:
// Basic request
Ext.Ajax.request({
url: 'foo.php',
success: someFn,
failure: otherFn,
headers: {
'my-header': 'foo'
},
params: { foo: 'bar' }
});
So, in the case of session timeout, you could (for example) construct a JSON response, which would contain some error code (defined by you), and an error message to be shown to the user. The callback function should then check if this error is returned from the server, and take necessary actions (show error message, redirect to login page, etc.) when that happens.
Note that in the above case, from ExtJS viewpoint, the Ajax request would actually be successful. When the HTTP request fails altogether (HTTP errors like 403 and such), the Ajax request is considered unsuccessful. This is important because it is usually possible to define different callback functions for successful and unsuccessful requests (as in the above sample code).
You can mock the timeout session...
var keepaliveHandler = new Ext.util.DelayedTask(function(){
Ext.Ajax.request({
url : '/keepalive',
method : 'GET',
success: function(response, options){
//dummy server call each 60 seconds
keepaliveHandler.delay(60000);
}
});
});
var timeoutHandler = new Ext.util.DelayedTask(function(){
//invalidate session
Ext.Ajax.request({
url : '/logout',
method : 'GET',
success: function(response, options){
Ext.MessageBox.show({
title: MessagesMap.getMessage('session.closed'),
msg: MessagesMap.getMessage('session.closed.message'),
buttons: Ext.MessageBox.OK,
fn: function() {
window.location.pathname = '/';
},
icon: Ext.MessageBox.WARNING
});
}
});
});
if(Ext.ux.SystemProperties.isLogged) {
keepaliveHandler.delay(60000);
timeoutHandler.delay(Ext.ux.SystemProperties.timeout);
//check for mouse movements
document.body.onmousemove = function(e) {
timeoutHandler.delay(Ext.ux.SystemProperties.timeout);
};
}
url = "http://example.com"
new Ajax.Request(url, {
onComplete: function(transport) {
alert(transport.status);
}
});
I'd like that to return a status of 200 if the site is working, or 500 if it is not working, etc.. But that code is returning 0 all the time.
Ultimately, I want to have a setinterval function that regularly pings a website for uptime status.
With JQuery you should get your status with a code similar to what you have, and it will be something like this:
$.ajax({
url: 'some.url.com',
type: 'POST',
complete: function(transport) {
if(transport.status == 200) {
alert('Success');
} else {
alert('Failed');
}
}
});
And if you want to use prototype your code should only add this:
onXYZ:function(transport){
}
In the text above XYZ should be replaced by the http status code you want to catch for the response.
Hope this helps
Ajax libraries don't "return status codes" themselves; that code is the HTTP response code returned in the response from the server. A status code of 200 indicates success; 404 indicates "not found", etc.
It's probable that a response code of 0 means the request wasn't even attempted. Is the request URL under the same domain (subdomain, if applicable) as that which the page is coming from? If not, then you may be running into problems with the same-origin policy, which prevents scripts from creating arbitrary requests.
To work around this, you'll need to proxy the data on the server side; for example using a script/framework handler/whatever which executes the web request and passes the data back down to clients. Call the "local" proxy instead of the remote data source.
Prototype has onXYZ callbacks, for example:
new Ajax.Request(url, {
method: 'get',
on500: function(transport) {
alert("failed!");
},
onSuccess: function(transport) {
alert("success!");
}
});
On thing though, if the website is down (as in, not reachable), it will not return a 500 error, so your approach isn't very good for starters.
I was able to make remote domains work by creating a server side proxy file to pass the status code through. I used the code on this post to create a asp.net page that would just set the status code of the page to the web request status code.
I then used the ajax example that Chermosillo provided like so.
$.ajax({
url: 'URLTestProxy.aspx?url=http://some.url.com',
type: 'POST',
complete: function(transport) {
if(transport.status == 200) {
alert('Success');
} else {
alert('Failed');
}
}
});
This way here you can get around the same origin policy and still get the status code of the remote url.
It may be helpful to know that the transport param in the example is an XMLHttpRequest object. Full details of the methods and properties available from this object can be found here:
http://www.w3.org/TR/XMLHttpRequest/#the-xmlhttprequest-interface
Most notable in the context of this question are the response items:
readonly attribute unsigned short status;
readonly attribute DOMString statusText;
DOMString getResponseHeader(DOMString header);
DOMString getAllResponseHeaders();
readonly attribute DOMString responseText;
readonly attribute Document responseXML;
You should be able to get any arbitrary header with the getResponseHeader() method.
For jQuery you might try:
complete: function(transport, textstatus){
alert(transport.getResponseHeader("Status"))
}
warning: not tested