safari 6 caching POST requests [duplicate] - ajax

Since the upgrade to iOS 6, we are seeing Safari's web view take the liberty of caching $.ajax calls. This is in the context of a PhoneGap application so it is using the Safari WebView. Our $.ajax calls are POST methods and we have cache set to false {cache:false}, but still this is happening. We tried manually adding a TimeStamp to the headers but it did not help.
We did more research and found that Safari is only returning cached results for web services that have a function signature that is static and does not change from call to call. For instance, imagine a function called something like:
getNewRecordID(intRecordType)
This function receives the same input parameters over and over again, but the data it returns should be different every time.
Must be in Apple's haste to make iOS 6 zip along impressively they got too happy with the cache settings. Has anyone else seen this behavior on iOS 6? If so, what exactly is causing it?
The workaround that we found was to modify the function signature to be something like this:
getNewRecordID(intRecordType, strTimestamp)
and then always pass in a TimeStamp parameter as well, and just discard that value on the server side. This works around the issue.

After a bit of investigation, turns out that Safari on iOS6 will cache POSTs that have either no Cache-Control headers or even "Cache-Control: max-age=0".
The only way I've found of preventing this caching from happening at a global level rather than having to hack random querystrings onto the end of service calls is to set "Cache-Control: no-cache".
So:
No Cache-Control or Expires headers = iOS6 Safari will cache
Cache-Control max-age=0 and an immediate Expires = iOS6 Safari will cache
Cache-Control: no-cache = iOS6 Safari will NOT cache
I suspect that Apple is taking advantage of this from the HTTP spec in section 9.5 about POST:
Responses to this method are not cacheable, unless the response
includes appropriate Cache-Control or Expires header fields. However,
the 303 (See Other) response can be used to direct the user agent to
retrieve a cacheable resource.
So in theory you can cache POST responses...who knew. But no other browser maker has ever thought it would be a good idea until now. But that does NOT account for the caching when no Cache-Control or Expires headers are set, only when there are some set. So it must be a bug.
Below is what I use in the right bit of my Apache config to target the whole of my API because as it happens I don't actually want to cache anything, even gets. What I don't know is how to set this just for POSTs.
Header set Cache-Control "no-cache"
Update: Just noticed that I didn't point out that it is only when the POST is the same, so change any of the POST data or URL and you're fine. So you can as mentioned elsewhere just add some random data to the URL or a bit of POST data.
Update: You can limit the "no-cache" just to POSTs if you wish like this in Apache:
SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST

I hope this can be of use to other developers banging their head against the wall on this one. I found that any of the following prevents Safari on iOS 6 from caching the POST response:
adding [cache-control: no-cache] in the request headers
adding a variable URL parameter such as the current time
adding [pragma: no-cache] in the response headers
adding [cache-control: no-cache] in the response headers
My solution was the following in my Javascript (all my AJAX requests are POST).
$.ajaxSetup({
type: 'POST',
headers: { "cache-control": "no-cache" }
});
I also add the [pragma: no-cache] header to many of my server responses.
If you use the above solution be aware that any $.ajax() calls you make that are set to global: false will NOT use the settings specified in $.ajaxSetup(), so you will need to add the headers in again.

Simple solution for all your web service requests, assuming you're using jQuery:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
// you can use originalOptions.type || options.type to restrict specific type of requests
options.data = jQuery.param($.extend(originalOptions.data||{}, {
timeStamp: new Date().getTime()
}));
});
Read more about the jQuery prefilter call here.
If you aren't using jQuery, check the docs for your library of choice. They may have similar functionality.

I just had this issue as well in a PhoneGap application. I solved it by using the JavaScript function getTime() in the following manner:
var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);
I wasted a few hours figuring this out. It would have been nice of Apple to notify developers of this caching issue.

I had the same problem with a webapp getting data from ASP.NET webservice
This worked for me:
public WebService()
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
...
}

Finally, I've a solution to my uploading problem.
In JavaScript:
var xhr = new XMLHttpRequest();
xhr.open("post", 'uploader.php', true);
xhr.setRequestHeader("pragma", "no-cache");
In PHP:
header('cache-control: no-cache');

From my own blog post iOS 6.0 caching Ajax POST requests:
How to fix it: There are various methods to prevent caching of requests. The recommended method is adding a no-cache header. This is how it is done.
jQuery:
Check for iOS 6.0 and set Ajax header like this:
$.ajaxSetup({ cache: false });
ZeptoJS:
Check for iOS 6.0 and set the Ajax header like this:
$.ajax({
type: 'POST',
headers : { "cache-control": "no-cache" },
url : ,
data:,
dataType : 'json',
success : function(responseText) {…}
Server side
Java:
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Make sure to add this at the top the page before any data is sent to the client.
.NET
Response.Cache.SetNoStore();
Or
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
PHP
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.

This JavaScript snippet works great with jQuery and jQuery Mobile:
$.ajaxSetup({
cache: false,
headers: {
'Cache-Control': 'no-cache'
}
});
Just place it somewhere in your JavaScript code (after jQuery is loaded, and best before you do AJAX requests) and it should help.

You can also fix this issue by modifying the jQuery Ajax function by doing the following (as of 1.7.1) to the top of the Ajax function (function starts at line 7212). This change will activate the built-in anti-cache feature of jQuery for all POST requests.
(The full script is available at http://dl.dropbox.com/u/58016866/jquery-1.7.1.js.)
Insert below line 7221:
if (options.type === "POST") {
options.cache = false;
}
Then modify the following (starting at line ~7497).
if (!s.hasContent) {
// If data is available, append data to URL
if (s.data) {
s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}
// Get ifModifiedKey before adding the anti-cache parameter
ifModifiedKey = s.url;
// Add anti-cache in URL if needed
if (s.cache === false) {
var ts = jQuery.now(),
// Try replacing _= if it is there
ret = s.url.replace(rts, "$1_=" + ts);
// If nothing was replaced, add timestamp to the end.
s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}
}
To:
// More options handling for requests with no content
if (!s.hasContent) {
// If data is available, append data to URL
if (s.data) {
s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}
// Get ifModifiedKey before adding the anti-cache parameter
ifModifiedKey = s.url;
}
// Add anti-cache in URL if needed
if (s.cache === false) {
var ts = jQuery.now(),
// Try replacing _= if it is there
ret = s.url.replace(rts, "$1_=" + ts);
// If nothing was replaced, add timestamp to the end.
s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}

A quick work-around for GWT-RPC services is to add this to all the remote methods:
getThreadLocalResponse().setHeader("Cache-Control", "no-cache");

This is an update of Baz1nga's answer. Since options.data is not an object but a string I just resorted to concatenating the timestamp:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
if (originalOptions.type == "post" || options.type == "post") {
if (options.data && options.data.length)
options.data += "&";
else
options.data = "";
options.data += "timeStamp=" + new Date().getTime();
}
});

In order to resolve this issue for WebApps added to the home screen, both of the top voted workarounds need to be followed. Caching needs to be turned off on the webserver to prevent new requests from being cached going forward and some random input needs to be added to every post request in order for requests that have already been cached to go through. Please refer to my post:
iOS6 - Is there a way to clear cached ajax POST requests for webapp added to home screen?
WARNING: to anyone who implemented a workaround by adding a timestamp to their requests without turning off caching on the server. If your app is added to the home screen, EVERY post response will now be cached, clearing safari cache doesn't clear it and it doesn't seem to expire. Unless someone has a way to clear it, this looks like a potential memory leak!

Things that DID NOT WORK for me with an iPad 4/iOS 6:
My request containing: Cache-Control:no-cache
//asp.net's:
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache)
Adding cache: false to my jQuery ajax call
$.ajax(
{
url: postUrl,
type: "POST",
cache: false,
...
Only this did the trick:
var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);

That's the work around for GWT-RPC
class AuthenticatingRequestBuilder extends RpcRequestBuilder
{
#Override
protected RequestBuilder doCreate(String serviceEntryPoint)
{
RequestBuilder requestBuilder = super.doCreate(serviceEntryPoint);
requestBuilder.setHeader("Cache-Control", "no-cache");
return requestBuilder;
}
}
AuthenticatingRequestBuilder builder = new AuthenticatingRequestBuilder();
((ServiceDefTarget)myService).setRpcRequestBuilder(builder);

My workaround in ASP.NET (pagemethods, webservice, etc.)
protected void Application_BeginRequest(object sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
}

While adding cache-buster parameters to make the request look different seems like a solid solution, I would advise against it, as it would hurt any application that relies on actual caching taking place. Making the APIs output the correct headers is the best possible solution, even if that's slightly more difficult than adding cache busters to the callers.

For those that use Struts 1, here is how I fixed the issue.
web.xml
<filter>
<filter-name>SetCacheControl</filter-name>
<filter-class>com.example.struts.filters.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SetCacheControl</filter-name>
<url-pattern>*.do</url-pattern>
<http-method>POST</http-method>
</filter-mapping>
com.example.struts.filters.CacheControlFilter.js
package com.example.struts.filters;
import java.io.IOException;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
public class CacheControlFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
resp.setHeader("Expires", "Mon, 18 Jun 1973 18:00:00 GMT");
resp.setHeader("Last-Modified", new Date().toString());
resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
resp.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}

I was able to fix my problem by using a combination of $.ajaxSetup and appending a timestamp to the url of my post (not to the post parameters/body). This based on the recommendations of previous answers
$(document).ready(function(){
$.ajaxSetup({ type:'POST', headers: {"cache-control","no-cache"}});
$('#myForm').submit(function() {
var data = $('#myForm').serialize();
var now = new Date();
var n = now.getTime();
$.ajax({
type: 'POST',
url: 'myendpoint.cfc?method=login&time='+n,
data: data,
success: function(results){
if(results.success) {
window.location = 'app.cfm';
} else {
console.log(results);
alert('login failed');
}
}
});
});
});

I think you have already resolved your issue, but let me share an idea about web caching.
It is true you can add many headers in each language you use, server side, client side, and you can use many other tricks to avoid web caching, but always think that you can never know from where the client are connecting to your server, you never know if he are using a Hotel “Hot-Spot” connection that uses Squid or other caching products.
If the users are using proxy to hide his real position, etc… the real only way to avoid caching is the timestamp in the request also if is unused.
For example:
/ajax_helper.php?ts=3211321456
Then every cache manager you have to pass didnt find the same URL in the cache repository and go re-download the page content.

Depending on the app you can trouble shoot the issue now in iOS 6 using Safari>Advanced>Web Inspector so that is helpful with this situation.
Connect the phone to Safari on a Mac an then use the developer menu to trouble shoot the web app.
Clear the website data on the iPhone after update to iOS6, including specific to the app using a Web View. Only one app had an issue and this solved it during IOS6 Beta testing way back, since then no real problems.
You may need to look at your app as well, check out NSURLCache if in a WebView in a custom app.
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003754
I guess depending on the true nature of your problem, implementation, etc. ..
Ref: $.ajax calls

I found one workaround that makes me curious as to why it works. Before reading Tadej's answer concerning ASP.NET web service, I was trying to come up with something that would work.
And I'm not saying that it's a good solution, but I just wanted to document it here.
main page: includes a JavaScript function, checkStatus(). The method calls another method which uses a jQuery AJAX call to update the html content. I used setInterval to call checkStatus(). Of course, I ran into the caching problem.
Solution: use another page to call the update.
On the main page, I set a boolean variable, runUpdate, and added the following to the body tag:
<iframe src="helper.html" style="display: none; visibility: hidden;"></iframe>
In the of helper.html:
<meta http-equiv="refresh" content="5">
<script type="text/javascript">
if (parent.runUpdate) { parent.checkStatus(); }
</script>
So, if checkStatus() is called from the main page, I get the cached content. If I call checkStatus from the child page, I get updated content.

While my login and signup pages works like a charm in Firefox, IE and Chrome... I've been struggling with this issue in Safari for IOS and OSX, few months ago I found a workaround on the SO.
<body onunload="">
OR via javascript
<script type="text/javascript">
window.onunload = function(e){
e.preventDefault();
return;
};
</script>
This is kinda ugly thing but works for a while.
I don't know why, but returning null to the onunload event the page do not get cached in Safari.

We found that older iPhones and iPads, running iOS versions 9 & 10, occasionally return bogus blank AJAX results, perhaps due to Apple's turning down CPU speed. When returning the blank result, iOS does not call the server, as if returning a result from cache. Frequency varies widely, from roughly 10% to 30% of AJAX calls return blank.
The solution is hard to believe. Just wait 1s and call again. In our testing, only one repeat was all that was ever needed, but we wrote the code to call up to 4 times. We're not sure if the 1s wait is required, but we didn't want to risk burdening our server with bursts of repeated calls.
We found the problem happened with two different AJAX calls, calling on different API files with different data. But I'm concerned it could happen on any AJAX call. We just don't know because we don't inspect every AJAX result and we don't test every call multiple times on old devices.
Both problem AJAX calls were using: POST, Asynchronously = true, setRequestHeader = ('Content-Type', 'application/x-www-form-urlencoded')
When the problem happens, there's usually only one AJAX call going on. So it's not due to overlapping AJAX calls. Sometimes the problem happens when the device is busy, but sometimes not, and without DevTools we don't really know what's happening at the time.
iOS 13 doesn't do this, nor Chrome or Firefox. We don't have any test devices running iOS 11 or 12. Perhaps someone else could test those?
I'm noting this here because this question is the top Google result when searching for this problem.

It worked with ASP.NET only after adding the pragma:no-cache header in IIS. Cache-Control: no-cache was not enough.

I suggest a workaround to modify the function signature to be something like this:
getNewRecordID(intRecordType, strTimestamp)
and then always pass in a TimeStamp parameter as well, and just discard that value on the server side. This works around the issue.

Related

Simple Ajax Code That Used To Work No Longer Works

I have a custom webserver, and some content that has been working for probably 18 months or more. The code has not been touched in all that time. But, I now find one feature, which depends on Ajax, is no longer working. The problem is on the browser side. Sadly, the Ajax code was found using Google, and even when I customized it, I didn't really understand it, but it has worked until some time in the last 6 months or so. Now that it's no longer working, I'm kinda lost....
What the code does is pretty simple. My HTML form is a tab control. One of the tabs is used for displaying error messages. The Ajax code sends a GET request for "\ATCStatus.txt" roughly once per second. The server responds with:
HTTP/1.1
Server: arduino
Content-Type: text/plain
#ATCErrorFlag#
where #ATCErrorFlag# gets replaced with wither "true" or "false". If "false" is returned, nothing happens. If "true" is returned, then the Ajax code sends a request for "\ATCErrorPage.htm", which switches to the error tab, and displays the error message.
The server receives the requests, processes them, and sends the correct response, but Ajax code acts like no response was ever received, and I can't figure out why.
Anyone here know enough Ajax to have a clue?
Here is the Ajax code:
setInterval(PollATCError, 1000);
function PollATCError()
{
var xhr;
if (window.XMLHttpRequest)
xhr = new XMLHttpRequest();
else if (window.ActiveXObject)
xhr = new ActiveXObject("Msxml2.XMLHTTP");
else
throw new Error("Ajax is not supported by your browser");
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4 && xhr.status == 200)
{
clearTimeout(xhrTimeout);
var response = xhr.responseText;
if (response == "false") {
// Do nothing
} else if (response == "true") {
// else, throw up Error Page
window.location.replace('ATCErrorPage.htm');
//document.getElementById("tab4event").click();
}
}
}
xhr.open('GET', 'ATCStatus.txt', true);
xhr.send(null);
var xhrTimeout = setTimeout("ajaxTimeout();", 900);
function ajaxTimeout()
{
xhr.abort();
// Note that at this point you could try to send a notification to the
// server that things failed, using the same xhr object.
}
}
What seems especially odd is that I don't ever seem to get any state change notifications. If I make the first line of the state change handler an alert(), the alert never comes up. The request does go to the server, the correct response is sent back to the client, but seems to never be seen by the XMLHttpRequest object. Even the 900mSec timeout never happens.
This used to work very nicely! What has gone wrong?? How can I get to the bottom of this?
Regards,
Ray L.

AngularJS disable partial caching on dev machine

I have problem with caching partials in AngularJS.
In my HTML page I have:
<body>
<div ng-view></div>
<body>
where my partials are loaded.
When I change HTML code in my partial, browser still load old data.
Is there any workaround?
For Development you can also deactivate the browser cache - In Chrome Dev Tools on the bottom right click on the gear and tick the option
Disable cache (while DevTools is open)
Update: In Firefox there is the same option in Debugger -> Settings -> Advanced Section (checked for Version 33)
Update 2: Although this option appears in Firefox some report it doesn't work. I suggest using firebug and following hadaytullah answer.
Building on #Valentyn's answer a bit, here's one way to always automatically clear the cache whenever the ng-view content changes:
myApp.run(function($rootScope, $templateCache) {
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
});
});
As mentioned in the other answers, here and here, the cache can be cleared by using:
$templateCache.removeAll();
However as suggested by gatoatigrado in the comment, this only appears to work if the html template was served without any cache headers.
So this works for me:
In angular:
app.run(['$templateCache', function ( $templateCache ) {
$templateCache.removeAll(); }]);
You may be adding cache headers in a variety of ways but here are a couple of solutions that work for me.
If using IIS, add this to your web.config:
<location path="scripts/app/views">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
If using Nginx, you can add this to your config:
location ^~ /scripts/app/views/ {
expires -1;
}
Edit
I just realised that the question mentioned dev machine but hopefully this may still help somebody...
If you are talking about cache that is been used for caching of templates without reloading whole page, then you can empty it by something like:
.controller('mainCtrl', function($scope, $templateCache) {
$scope.clearCache = function() {
$templateCache.removeAll();
}
});
And in markup:
<button ng-click='clearCache()'>Clear cache</button>
And press this button to clear cache.
Solution For Firefox (33.1.1) using Firebug (22.0.6)
Tools > Web-Tools > Firebug > Open Firebug.
In the Firebug views go to the "Net" view.
A drop down menu symbol will appear next to "Net" (title of the view).
Select "Disable Browser Cache" from the drop down menu.
This snippet helped me in getting rid of template caching
app.run(function($rootScope, $templateCache) {
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if (typeof(current) !== 'undefined'){
$templateCache.remove(current.templateUrl);
}
});
});
The details of following snippet can be found on this link:
http://oncodesign.io/2014/02/19/safely-prevent-template-caching-in-angularjs/
I'm posting this just to cover all possibilities since neither of the other solutions worked for me (they threw errors due angular-bootstrap template dependencies, among others).
While you are developing/debugging a specific template, you can ensure it always refreshes by included a timestamp in the path, like this:
$modal.open({
// TODO: Only while dev/debug. Remove later.
templateUrl: 'core/admin/organizations/modal-selector/modal-selector.html?nd=' + Date.now(),
controller : function ($scope, $modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
}
});
Note the final ?nd=' + Date.now() in the templateUrl variable.
As others have said, defeating caching completely for dev purposes can be done easily without changing code: use a browser setting or a plugin. Outside of dev, to defeat Angular template caching of route-based templates, remove the template URL from the cache during $routeChangeStart (or $stateChangeStart, for UI Router) as Shayan showed. However, that does NOT affect the caching of templates loaded by ng-include, because those templates are not loaded through the router.
I wanted to be able to hotfix any template, including those loaded by ng-include, in production and have users receive the hotfix in their browser quickly, without having to reload the entire page. I'm also not concerned about defeating HTTP caching for templates. The solution is to intercept every HTTP request that the app makes, ignore those that are not for my app's .html templates, then add a param to the template's URL that changes every minute. Note that the path-checking is specific to the path of your app's templates. To get a different interval, change the math for the param, or remove the % completely to get no caching.
// this defeats Angular's $templateCache on a 1-minute interval
// as a side-effect it also defeats HTTP (browser) caching
angular.module('myApp').config(function($httpProvider, ...) {
$httpProvider.interceptors.push(function() {
return {
'request': function(config) {
config.url = getTimeVersionedUrl(config.url);
return config;
}
};
});
function getTimeVersionedUrl(url) {
// only do for html templates of this app
// NOTE: the path to test for is app dependent!
if (!url || url.indexOf('a/app/') < 0 || url.indexOf('.html') < 0) return url;
// create a URL param that changes every minute
// and add it intelligently to the template's previous url
var param = 'v=' + ~~(Date.now() / 60000) % 10000; // 4 unique digits every minute
if (url.indexOf('?') > 0) {
if (url.indexOf('v=') > 0) return url.replace(/v=[0-9](4)/, param);
return url + '&' + param;
}
return url + '?' + param;
}
If you are using UI router then you can use a decorator and update $templateFactory service and append a query string parameter to templateUrl, and the browser will always load the new template from the server.
function configureTemplateFactory($provide) {
// Set a suffix outside the decorator function
var cacheBust = Date.now().toString();
function templateFactoryDecorator($delegate) {
var fromUrl = angular.bind($delegate, $delegate.fromUrl);
$delegate.fromUrl = function (url, params) {
if (url !== null && angular.isDefined(url) && angular.isString(url)) {
url += (url.indexOf("?") === -1 ? "?" : "&");
url += "v=" + cacheBust;
}
return fromUrl(url, params);
};
return $delegate;
}
$provide.decorator('$templateFactory', ['$delegate', templateFactoryDecorator]);
}
app.config(['$provide', configureTemplateFactory]);
I am sure you can achieve the same result by decorating the "when" method in $routeProvider.
I found that the HTTP interceptor method works pretty nicely, and allows additional flexibility & control. Additionally, you can cache-bust for each production release by using a release hash as the buster variable.
Here is what the dev cachebusting method looks like using Date.
app.factory('cachebustInjector', function(conf) {
var cachebustInjector = {
request: function(config) {
// new timestamp will be appended to each new partial .html request to prevent caching in a dev environment
var buster = new Date().getTime();
if (config.url.indexOf('static/angular_templates') > -1) {
config.url += ['?v=', buster].join('');
}
return config;
}
};
return cachebustInjector;
});
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('cachebustInjector');
}]);
Here is another option in Chrome.
Hit F12 to open developer tools. Then Resources > Cache Storage > Refresh Caches.
I like this option because I don't have to disable cache as in other answers.
There is no solution to prevent browser/proxy caching since you cannot have the control on it.
The other way to force fresh content to your users it to rename the HTML file! Exactly like https://www.npmjs.com/package/grunt-filerev does for assets.

Jquery .get() not working in Internet Explorer

I'm having a problem with, guess what, IE8. The following code, simplified for clarity, does not work at all:
alert('before get');
$.get(getActivityURL('ActionName',{
ts: new Date().getTime(), ...other params...}),
{cache:false;},
function (xml) {
alert("in get callback");
},'xml'); // End $.get()
alert('in after get');
The getActivityUrl() outputs a valid URL with request parameters.
This works correctly in FF and Chrome. However, in IE8, this doesn't even get into the $.get() callback. I get the "before" and "after" alerts, but not the "in" alert and indeed, nothing happens and the request is NOT sent. I don't really know what to think here.
The response headers are "Content-Type:application/xml; charset:iso-8859-1" as confirmed in FF.
EDIT: $.post() doesn't work, either.
IE is infamous for caching. So you need to make sure you are not getting a cached result.
You can disable caching globally by setting the cache property value to false in the ajaxStart method.
$.ajaxSetup({
cache: false
});
Or If you want to eliminate the cached result in a specific ajax call, Append a unique number to the end of the url. You may use the $.now() method to get a unique number
$.get("someurl.php?" + $.now() ,function(result) {
// do something with result
});
$.now() method return a number representing the current time.
I'm not sure if it is a problem but try to remove ";" in {cache:false}
IE doesn't like any additional stuff in {}, eg
{a:a,b:b,c:c,} will work in FF but not in IE
I think so there is Cache problem in IE.
So add Math.random(), one more parameter at the end like "&mathRandom="+Math.random();
Because IE will recognise same request as previous one so it will give data from cache instead of firing request.
$J.get(getActivityURL('ActionName'
// End $.get()
Is this correct? I mean $J... Are you using more than one JS framework or something?
have u tried:
$.ajax({
url: getActivityURL('ActionName',{ts: new Date().getTime(), ...other params...}),
data: data,
success: function (xml) {
alert("in get callback");
},
dataType: 'xml'
});
Just a guess
EDIT:
I found a interesting thread that might help you, check this out:
jQuery issue in Internet Explorer 8

JQuery - It fails on IE7. Crossbrowser compatibility?

I tried to open a post time ago about this problem (here), thinking i was wrong making the code. Now more or less i've understood that some version of Jquery with my code doesnt work on IE7. What's Happening? I also tried to open a post on JQuery official forum (link) but no one reply. Anyway, in my old website i used to work with jquery-1.3.2.min.js , and i didnt problems. Now, i need to use the .delegate() function, so I include the jquery-1.4.2.min.js library.
Above you can see the usual code I used in my old application :
// html page
prova
// javascript page
function pmNew(mexid) {
var time = new Date;
$.ajax({
type: 'POST',
url: './folder/ajax.php',
data: 'mexid='+escape(mexid)+'&id=pmnew',
success: function(msg) {
alert(msg);
}
});
return false;
}
// asynchf.php
if($_POST['id']=="pmnew") {
echo "please, i will just print this";
}
With some suggestions by some users of this website, i edited these functions :
// html page
prova
// javascript page
function pmNew(mexid) {
var time = new Date;
$.ajax({
type: 'POST',
cache: false,
url: './folder/ajax.php' + '?dummy=' + time.getTime(),
data: 'mexid='+escape(mexid)+'&id=pmnew',
success: function(msg) {
alert(msg);
}
});
return false;
}
// asynchf.php
if($_POST['id']=="pmnew") {
echo "please, i will just print this";
}
But it STILL DOESNT WORK on IE7. Firefox, Chrome, it rocks. It works on IE7 only if i load the page, i try (and i get the error message), i reload (F5) and i retry. Or, as i said before, i change the version of Jquery :)
I loaded a testpage on a real server (so you can check yourself this problem) : click here
I hope someone can help me with this big trouble.
Cheers
The reason behind this bug is when you are using relative URLs on IE7, it actually adds your base url (or wherever your page is loaded from e.g. if you place a relative url on your home page your relative URL would actually be http://gabbatracklistworld.com/http://gabbatracklistworld.com/folder/ajax.php)
I just came across your question here on SO while searching for a solution on some same problem I had myself a few minutes ago. There's actually an article from microsoft's blog that explains how IE7 handle relative urls (which is funny because it just shows that they are proud of how their stupid browser works)
Seeing that you have no answer yet, I'd put my solution here for future reference and other devs too.
What I did is use substring() to strip the instances of my base url forcing the ajax request to use the actual relative URL.
Can you add this argument to your .Ajax options:
error:function(xhr, status, errorThrown) {
alert(errorThrown+'\n'+status+'\n'+xhr.statusText);
},
and reply with the message ?

problem using HTML5 for Cross-origin resource sharing

I am new to this site and had been successfully using the "HTML5" Cross-origin resource sharing (CORS) to POST data to my server. I just recently tried to include GETs in that as we are trying to have all of our communications be non-reliant on a JavaScript library. In doing so I have run into an odd issue that seems somewhat fixable for Firefox but is still misbehaving in all the WebKit browsers. Essentially anything that returns a status of <200 or >300 is just coming in as a status of 0. This makes it next to impossible to do error handling.
For Firefox, I am able to put a random string on the end of the request to prevent it from being cached; thereby fixing the 304s at least. This however does not work at all for me in Chrome/Safari. Here is a sample of my code:
xhr_request: function(type,url, data, callbacks, form){
var form = (typeof(form)!=="undefined")?form:null;
var xhr = new XMLHttpRequest();
var response;
data = com.ticommunity.obj_to_string(data);
xhr.open(type, url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("X-TxId", com.ticommunity.keyGen());
xhr.withCredentials = true;
xhr.send(data);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
response = xhr.responseText;
com.ticommunity.comm.request_callback(response, callbacks, form);
}else{`//****this is where the 0 Status keeps coming up***`
response = xhr.status;
com.ticommunity.comm.request_callback(response, callbacks, form);
}
}
}
}
Has anyone else run into something similar and come up with a work-around? Am I just doing something stupid on my end? Any help is greatly appreciated.
EDIT: I realized the 0 is what is supposed to happen per the spec, but I REALLY need to be able to trap for these situations and do some other handling.
I haven't seen this issue specifically, but I wonder if you'd have better luck using a different xhr event, such as xhr.onload. You can trust onload to fire on successful responses, so there's no need to check xhr.status. Here's a complete list of events if you need to trap on something else:
http://www.w3.org/TR/XMLHttpRequest2/#events

Resources