10

I have this bizarre issue with Chrome. It quite often appears to cache PUT requests.

The Details: I have an app using backbone.js and when trying to persist some changes to a model (backbone automatically generates a PUT request), Chrome just wont send that request to the server. It works perfectly fine in Firefox and IE (haven't seen the issue in Safari so far).

Here's a screenshot from the Chrome developer tools' Network tab. As you can see, the response for the PUT request is being returned from cache (the request doesn't hit the server!!) Chrome caches PUT request

Here's a screenshot of the header details of that same request. Once again, it's evident that Chrome doesn't bother sending the PUT request to the server. Chrome cached PUT request header

The payload of the request is JSON data. Any thoughts as to why this is happening / what I'm doing wrong?

UPDATE: Chromium has confirmed that this is indeed a bug on it's end (thanks Jan Hančič).

TEMPORARY SOLUTION I ended up overriding Backbone.sync method and appending a timestamp to the querystring of PUT, POST and DELETE requests so that they are always unique:

if(!options.data && model && (method == 'create' || method == 'update' || method == 'delete')) {
    params.url += (params.url.indexOf('?') == -1 ? '?' : '&') + '_=' + new Date().getTime();
}
anushr
  • 3,342
  • 3
  • 29
  • 50
  • 2
    Does this only happen if you send data in the PUT request, that you'll already send before or does this also occure if you change the data to be submitted and trigger the request again? – Robin Drexler Aug 01 '12 at 06:45
  • The response from the server doesn't change maybe that's why its cached. Like Robin said, change/correct the request – Zebra Aug 01 '12 at 06:46
  • 1
    The data definitely changes. However, I would think that it shouldn't matter whether the data has changed or not. A PUT really isn't a cacheable request type. It's meant to send data to the server, not fetch data. – anushr Aug 01 '12 at 06:48
  • 3
    This is probably related to this bug: http://code.google.com/p/chromium/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Pri%20Mstone%20ReleaseBlock%20OS%20Area%20Feature%20Status%20Owner%20Summary&groupby=&sort=&id=136320 – Jan Hančič Aug 01 '12 at 07:20
  • Nasty, I think this is specifically related to xhr, which implemented today will aggressively use the cache (not even issuing 304 expectant requests) – meandmycode Aug 01 '12 at 07:33
  • My Chrome 20 has a checkbox "Disable cache" under settings from Developer Tools – Claudiu Hojda Aug 01 '12 at 09:52

2 Answers2

4

I use extra parameter to avoid caching:

url += '?_dc=' + Math.random().toFixed(20).replace('.', '');

I don't interpret this parameter on server side.

EDIT: Besides of chrome there are a lot things could cache requests - user's proxy server for instance. I think additional query parameter is a good solution to keep out of caching.

Pavel Reznikov
  • 2,968
  • 1
  • 18
  • 17
  • I agree that would be the appropriate workaround. I tried doing that but unfortunately, since we use backbone.js, adding additional querystring parameters is quite difficult (unless someone has suggestions on how to have a request payload AND querystring param with backbone) – anushr Aug 01 '12 at 07:29
  • You could implement `sync` method for model. As I can see, you could pass `url` with `options` to `Backbone.sync` method. See http://backbonejs.org/#Sync and backbone's `sync` implementation for more details. You could wrap `Backbone.sync` and do all these stuff in one place. – Pavel Reznikov Aug 01 '12 at 07:39
  • I ended up overriding `Backbone.sync` and including the timestamp (`url += '?_=' + new Date().getTime()`) whenever there is a PUT, POST or DELETE request (apparently Chrome has issues with all 3) – anushr Aug 01 '12 at 21:47
0

Backbone use jQuery or Zepto to make the AJAX request. Assuming that you are using jQuery, set the cache off.

Run this to set the cache off in the overall application so you will not need to worry about cache:

$.ajaxSetup({
      cache : false
});

If keep the cache on is important for your business, I think that you could do something like this for specific no cache calls:

model.save({}, {cache:false});
Daniel Aranda
  • 6,426
  • 2
  • 21
  • 28
  • 1
    The `cache` property only takes effect on `GET` requests (as it should be). It does nothing for `PUT` requests. – anushr Aug 01 '12 at 21:32
  • I do not think so, I set cache false and I see that PUT requests has the noCache Query. – Daniel Aranda Aug 01 '12 at 23:29
  • Not really sure where did you get that wrong information about that cache only works for GET request, maybe Today you will doing overwrite on Backbone.Syncs, later when you only test $.ajaxSetup you will understand that it works. I have a lot of projects using Backbone.js and jQuery and I know that this line is enough. – Daniel Aranda Aug 01 '12 at 23:35
  • In the context of the question that was asked (specific to the Chrome bug), this solution does not work. – anushr Aug 02 '12 at 06:07