How to prevent Ajax/javascript result caching in browsers? - javascript

How to prevent browsers from caching Ajax results? I have and event triggered Ajax script the displays results only when the browsers data has been cleared.
Tested in IE6 and Firefox 3.0.10

The random URL works, but it's kind of a hack. HTTP has solutions built in that should work. Try using the solution indicated here. Basically, set the headers:
"Pragma": "no-cache",
"Cache-Control": "no-store, no-cache, must-revalidate, post-check=0, pre-check=0",
"Expires": 0,
"Last-Modified": new Date(0), // January 1, 1970
"If-Modified-Since": new Date(0)

Add a random query string to the URL you are sending.
E.g. if the Ajax request is sent to "http://www.xyz.com/a"
then add a random string at the end: "http://www.xyz.com/a?q=39058459ieutm39"

I've used the jQuery {cache: false} method and it worked like a charm.
The complete code example is like this:
$.ajaxSetup({cache: false});

There are two techniques for this that I'm aware of.
Add some sort of query string to the AJAX request URL so that it's always unique. A millisecond timestamp (perhaps combined with a random value) is good for this
Set HTTP cache control headers on the AJAX response so that the browser doesn't cache it

using jQuery you can set global ajax setting: { cache: false }. See it in jquery ajax docs

Related

How to trigger Spinner for file download or How to download file in browser if AngularJS $resource response received as an attachement with file name

I'm able to download successfully using below line of code in AngularJS controller.
$window.location.href =$rootScope.urlBase+'/dios/download/lineitemexcel/'+$routeParams.id
But, when data is large and it is taking longer time, for this reason I need to enable angular-Spinner. No way I could find a way to start spinner before the call and it should finish after file download finished in the browser.
Root Problem: How can I enable spinner with existing plugin in the project angular-spinner or usSpinnerService? if this has a solution I dont have next question.
To Solve this problem, I have gone through existing spinner working flow.
Spinner is working if there is $resource call.
Hence above url I tried by forming factory call like below:
Service:
factory('Dios', ['$resource','$rootScope',
function($resource, $rootScope){
return $resource($rootScope.urlBase+'/dios/:id/:status/:third/:fourth/:fifth/:pageNo', {}, {
get: {
method: 'GET'
},
update: {
method: 'PUT'
},
getexcel: {
method: 'GET',
transformResponse: function(data, headers,status){
var dataTransformed = {};
dataTransformed.data=data;
dataTransformed.headers=headers;
dataTransformed.status=status;
return dataTransformed;
}
}
});
}])
Controller:
Dios.getexcel({dios:'dios',third:'download',fourth:'lineitemexcel',fifth: $routeParams.id},function(data){
console.log(data);
]);
Using above factory call rest call with an Id of an Object. That Object I need to retrieve and process using Apache POI JAVA library , and Apache POI library will return as an attachement with response header properties in dev tools network tab as follows:
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Access-Control-Allow-Origin: http://10.218.39.45:9000
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Headers: Content-Type,X-Requested With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
Access-Control-Expose-Headers:
1,Access-Control-Allow-Origin,Access-Control-Allow-Credentials
Content-Disposition: attachment;
filename=LineItems-of_IO-1553-8531Testing_2018-09-18.xlsx
Content-Type: application/vnd.ms-excel
Transfer-Encoding: chunked
Date: Tue, 18 Sep 2018 08:33:46 GMT
In this way I'm able to get spinner but , I am not sure how to download response received as file with specified name in response headers.
using transformResponse: I am expecting responseheaders info, but it is not getting attached to headers in transformResponse:.
So Kindly help me to get spinner is getting triggered for window.location.href=url or help me how download the received data through $resource.
First this question has nothing to do with angularjs itself, this is pure js problem.
For download there are 2 options:
Download file using Ajax and then store it on disk using createObjectURL.
Download file usual way i.e. simple href.
These two are really different:
-1st wont work in some browsers
-1st gives you full access over request, you can comfortably handle errors etc.
-2nd start download in parallel, e.g. in chrome you can close tab with app, but download will still proceed
In 1st way showing spinner is relatively easy, you do it as for any other request.
In 2nd way you usually do not want to show spinner when download is in progress as browser will show progress for you. However, before download starts - before response came from server you sometimes may want to show some waiting and the only way this can be done is using cookies:
you add some param to download request e.g. my-cookie-id=cookie_123
server sets cookie cookie_123 in response
after link is clicked you check for this cookie value (e.g each 100ms)
when you see this cookie value, your file is started to download
I don't see any way to show spinner while downloading file directly using window.location.
But downloading file from response can be possible.
Can you please try below approach?
Delete trasnformResponse from $resource
Write a function to download file
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
$scope.downloadFile= function(data, fileName, contentType) {
var blob = new Blob([data], {
type: contentType
});
var url = URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
//hide spinner here
window.URL.revokeObjectURL(url);
}
Change you function call as
Dios.getexcel({dios:'dios',third:'download',fourth:'lineitemexcel',fifth: $routeParams.id},function(data, responseHeader){
$scope.downloadFile(data, responseHeader()['Content-Disposition'].split('filename=')[1] , responseHeader()['Content-Type']);
]);

how to detect a proxy using javascript

in a web page, is there a way to detect by javascript if a web browser is using a PAC file http://xxx.xx.xx.xxx/toto.pac ?
Notes : the same page can be viewd behind many PACs, i don't want to use a server end language, i can edit the toto PAC file if necessary. Regards
You could make an ajax request to a known external server (google.com) and then get the headers out of that request to see if the proxy headers are in the request...
var proxyHeader = 'via';
var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send();
var header = req.getResponseHeader(proxyHeader);
if (header) {
// we are on a proxy
}
Change proxyHeader to what ever your proxy adds to the response.
EDIT: You will have to add a conditional for supporting the IE implementation of XMLHttpRequest
EDIT:
I am on a proxy at work and I have just tested this code in jsfiddle and it works. Could be made prettier so that is supports IE and does an async get but the general functionality is there... http://jsfiddle.net/unvHW/
It turns out that detecting 'via' is much better...
Note that this solution will not work on every proxy and would probably only work if you are BEHIND the proxy :
Some proxies append a field in the response headers of an HTTP request which is called : X-Forwarded-For
Maybe you can achieve what you are trying to do with an AJAX request to google.com for example and check if the field is there.
Something like this :
$.ajax({
type: 'POST',
url:'http://www.google.com',
data: formData,
success: function(data, textStatus, request){
if(request.getResponseHeader('X-Forwarded-For')) !== undefined)
alert("Proxy detected !");
}
});
Edit: As Michael said, the X-Forwarded-For is only appended to requests. You'd better check for the response header your proxy puts in the response header.
No.
Browsers do not expose that sort of configuration data to websites.

$.getJSON fails on a successful http request

I'm calling the method in my page:
var dfd = $.Deferred(
$.getJSON(serviceAddress)
.done(function (result, status) {
bo.BusinessObject.DtosToaKoArray(result, resultList);
dfd.resolve(resultList);
})
.fail(function (result, status) {
logger.logError(result);
dfd.reject(result);
}));
return dfd;
After calling the JSON, the firebug shows that HttpRequest was successfull and the response header is like:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcV29ya3NwYWNlc1xNZWhyYW5cSW5mcmFzdHJ1Y3R1cmVcTWFpblxTb3VyY2VcSW5mcmFzdHJ1Y3R1cmVcU291cmNlXENhcmFuZS5HYWxheHkuV2ViQXBpXGFwaVxEYXRhUHJvdmlkZXJcTGlzdFNlcnZpY2Vc?=
X-Powered-By: ASP.NET
Date: Sun, 04 Aug 2013 05:57:39 GMT
Content-Length: 6684
but the problem is that instead of done callback, the fail callback is called with this result:
Object { readyState=4, status=404, statusText="error"}
What is wrong about my call that fails the successful http request?
Edit1.
My website (MyApp.Web) is on localhost:2771 and the calling service is in another project (MyApp.WebApi) on the localhost:4143
You will definitely run into some hurdles trying to make cross-origin requests. That includes port-to-port.
The solutions also depend on the service and what features it supports.
JSONP (or, JSON with Padding)
The service would need to accept a callback and output the JSON wrapped in a function call:
// http://...?callback=completeRequest
completeRequest(["json", "data"]);
The parameter can be a different name than callback. But, you can instruct jQuery to use it by including a placeholder parameter (...=?):
$.getJSON(serviceAddress + "?callback=?")
This can also be used in any browser as it's requested as a <script src> and the JSON will be parsed as JavaScript literals.
CORS
The service will need to support preflight, OPTIONS requests and respond with Access-Control-Allow-* headers.
Also, while most current browsers support CORS, this can be limited if you need to support older editions.
Otherwise, you'll need to create a proxy destination in your application (localhost:2771) that makes the cross-origin request server-side to the service (localhost:4143).
It might not be finding your target page and that's why you might be getting a 404 in your result object. Make sure that your serviceAddress is correct.
In addition to that When you specify: dataType: 'json' jQuery will fire the error event if the response cannot be parsed as JSON(despite the 200 reply). Make sure that the data returned from the server is valid JSON, you might want to validate the structure manually via JSONLint.
It might be any of these 2 problems.

Prevent browser from caching AJAX requests

I've setup an app and it works fantastic on Opera and Firefox, but on Google Chrome it caches the AJAX request and will give stale data!
http://gapps.qk.com.au is the app. When ran in Chrome it doesn't even send the AJAX requests, but when tried in another browser it always does the AJAX request and returns data.
Is there any method (Apache/PHP/HTML/JS) to stop Chrome from doing this behavior?
The AJAX call:
function sendAjax(action,domain,idelement) {
//Create the variables
var xmlhttp,
tmp,
params = "action=" + action
+ "&domain=" + encodeURIComponent(domain)
xmlhttp = new XMLHttpRequest();
//Check to see if AJAX request has been sent
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
$('#'+idelement).html(xmlhttp.responseText);
}
};
xmlhttp.open("GET", "ajax.php?"+params, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//console.log(params);
xmlhttp.send(params);
}
sendAjax('gapps','example.com','gapps');
The browser cache behaves differently on different settings. You should not depend on user settings or the user's browser. It's possible to make the browser ignore headers also.
There are two ways to prevent caching.
--> Change AJAX request to POST. Browsers don't cache POST requests.
--> Better Way & good way: add an additional parameter to your request with either the current time stamp or any other unique number.
params = "action=" + action
+ "&domain=" + encodeURIComponent(domain)
+ "&preventCache="+new Date();
Another alternative to the Javascript solution is to use custom headers:
In PHP it would look like this:
<?php
header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");//Dont cache
header("Pragma: no-cache");//Dont cache
header("Expires: Thu, 19 Nov 1981 08:52:00 GMT");//Make sure it expired in the past (this can be overkill)
?>
I was using jQuery ajax request when I ran into this problem.
According to jQuery API adding "cache: false" adds a timestamp like explained in the accepted answer:
This only works with GET and HEAD requests though but if you're using POST the browser doesn't cache your ajax request anyways. There's a but for IE8, check it out in the link if needed.
$.ajax({
type: "GET",
cache: false,
});
Below line of code worked for me.
$.ajaxSetup({ cache: false });

Determining what jQuery .ajax() resolves a string of redirects to

I'm aware that redirects are followed automatically, and that I have little/no control over that process. This is fine, but I'm still very interested in where my request ultimately ends up. Is it possible to see what url my request finally ends up at?
I do not want to rely on the returned HTML itself to tell me where I am.
Sample Code:
var originalURL = '/this/will/be/redirected';
$.ajax({
url: originalURL,
dataType: "html",
success: function(data, statusText, jqXHR) {
var endPointURL = insertMagicHere();
alert("Our query to " + original + " ended up at " + endPointURL + "!");
}
});
I'm looking around in jqXHR for it, but no luck so far. (Though, I'm new to all this, probably right under my nose)
So far as I know (and have testet) its only possible to detect IF there has been a redirect and how many redirects were made (but not TO where).
You can have a look my code:
var xhr = $.ajax({
url: originalURL,
dataType: "html",
success: function(data, statusText, jqXHR) {
console.log(data);
console.log(statusText);
console.log(jqXHR.getAllResponseHeaders());
}
});
The jqXHR.getAllResponseHeaders() output on my dev machine is like that:
Date: Fri, 05 Aug 2011 01:29:20 GMT
Server: ...
X-Powered-By: ...
Content-Length: 5
Keep-Alive: timeout=15, max=98
Connection: Keep-Alive
Content-Type: text/html
The Keep-Alive: timeout=15, max=98 is worth to have a deeper look at. No redirect result in a max=99 while ONE redirect results in a max=98
XMLHttpRequest.responseXML is a document meaning that it has a baseURI property which will be the location that the data was downloaded from. The main problem is that responseXML will only be set if you get an XML document back. In Firefox using overrideMimeType() works, despite reporting a syntax error in the document:
var r = new XMLHttpRequest();
r.open("GET", "http://google.com");
r.overrideMimeType("text/xml");
r.onload = function()
{
alert(r.responseXML.baseURI);
}
r.send(null);
Unfortunately, in Chrome you need a real XML document, overrideMimeType() doesn't help. And MSIE doesn't even implement this method (which isn't a big deal given that determining document source there seems impossible).
I'm not sure what magic they're using server side, but www.longURL.com does what you're talking about.
Their code sends a request to their server:
They have a jquery plug in: http://plugins.jquery.com/project/longurl
I'm not sure how to get the intermediate steps from it, but their website includes the redirects, so they must have figured out some way of doing it, which means they likely have some way of getting that.
To use it you'll have to look at their jquery plugin to figure out where they request the actual data.
EDIT
Allow me to correct that abysmally inadequate answer:
http://www.longURL.com has a service that expands shortened URLs.
Their main website (upon expanding a URL) tracks every redirect until you reach your final destination.
If you did whatever they were doing you might be able to do the same.
Unfortunately I don't know what they're doing (apart from sending their request to a server that probably listens specifically for 303s).
Their jQuery plugin may or may not be useful. If it exposes the redirects and you could figure out how to jimmy rig the system you might be able to get it through their service, otherwise you could create a shortened link to the initial link and get the results through their service anyway...sounds painful, but if you're unable to/unwilling to do server stuff, then that's probably your best option.

Categories

Resources