Bug Tracker

Modify

Ticket #12550 (closed bug: fixed)

Opened 19 months ago

Last modified 18 months ago

jQuery Ajax cache=false doesn't always work

Reported by: k@… Owned by: jaubourg
Priority: low Milestone: 1.9
Component: ajax Version: 1.8.1
Keywords: Cc:
Blocking: Blocked by:

Description

When sending an ajax request with the "cache" option set to "false" then sometimes the request is still answered from the browser cache. The reason is that fast machines and fast browsers (like Chrome) are able to send multiple Ajax requests in the same millisecond. jQuery only adds the current timestamp to the URL, looks like this is no longer enough.

This page demonstrates the problem:

 http://www.ailis.de/~k/permdata/20120917/jquerycache.html

Keep reloading the page on a fast machine and you will sometimes get a red "DUPLICATE" warning instead of a green "OK" indicating a timestamp which was already used for a previous request. On my machine this happens on every 3rd reload or so.

I recommend adding another value to the timestamp to prevent this problem. Maybe a static counter? That's how we workaround the problem currently.

Change History

comment:1 Changed 19 months ago by dmethvin

  • Priority changed from undecided to low
  • Status changed from new to open
  • Component changed from unfiled to ajax
  • Milestone changed from None to 1.9

You need a slower computer.

I suppose we could seed that static counter with the current time at page load and then just increment it on each request. If we do that I'm taking bets on how long we get a bug report that someone was expecting that value to represent the time the request was submitted.

comment:2 Changed 19 months ago by k@…

The documentation says jQuery adds a "timestamp". It doesn't say in which format. So maybe you can switch from an integer to a floating point number. You could remember the last used millisecond timestamp and then compare it on the next ajax request with the previous one. If they are the same then add a counter after the decimal point. When millisecond timestamp is newer than the previous one then reset the counter. Then you'll end up with timestamp parameters like this:

_=18236178231
_=18236178232
_=18236178232.001
_=18236178232.002
_=18236178233
_=18236178233.001
_=18236178233.002
_=18236178234

Doing it like this jQuery still sends a valid timestamp (Accuracy is somewhat faked but still as accurate as before) and can generate 1000 unique Ajax-URLs per millisecond. Should be enough even for my super computer (Which is only a standard i7 laptop) ;-)

And when JavaScript supports nanosecond timestamps some day then this counter hack could simply be replaced with a real high-precision timestamp.

comment:3 Changed 19 months ago by jaubourg

  • Owner set to jaubourg
  • Status changed from open to assigned

We surely have a bug here but I'd love to know what real-life application will make a gazillion requests to the same exact same URL within the same second... seems pretty innefficient to me (as in, why not group the requests?).

comment:4 Changed 19 months ago by jaubourg

@dmethvin Also, shouldn't we aim at fixing this sooner than later (ie. 1.8.2)? It's a minor behaviour change, I agree, but I can see how this situation will only present itself more often.

comment:5 Changed 19 months ago by dmethvin

It doesn't seem very common since this is the first report we've ever had. I'd really like to get 1.8.2 out without any regressions, and my concern is that someone has taken our "timestamp" description to be a pledge that it always represents the starting time of that ajax request. Turning the value into a floating point number might work though, at least that would be trimmed off if the server treated it like an integer. Do you think I'm anticipating a regression that won't occur?

comment:6 Changed 19 months ago by k@…

@jaubourg It's not a gazillion requests. Two requests are enough. It may work in 99% of all page requests but the hundredth visitor may trigger the error. I can't give you a good real-life example. In our case the browser has to request some unique server-side entity ID in various places. These places are pretty much independent from each other so they send their own ajax requests to the same URL and this sometimes happens in the same millisecond.

@dmethvin Maybe this is the first report for this problem because computers and browsers were not fast enough in the past to trigger this problem. Oh, BTW: Just noticed I get multiple duplicate timestamps in the demo page on every request when using Firefox. Looks like Firefox is even faster as Chrome. That's surprising to me, but off-topic ;-)

comment:7 Changed 19 months ago by kayahr

What about adding another parameter instead when the timestamp was already used in the previous ajax request? Then the timestamp parameter itself is not changed:

_=18236178231
_=18236178232
_=18236178232&__=1
_=18236178232&__=2
_=18236178233
_=18236178233&__=1
_=18236178233&__=2
_=18236178234

But maybe this makes trouble when there is already a parameter with two underscores as name...

comment:8 Changed 19 months ago by jaubourg

I don't really like the idea of adding too much logic (testing if the previous anticache param was the same then reset the counter or increment it). I'd like the fix to be as compact as possible. If we just add a counter at the end of the timestamp (string concatenation style) then, yes, we have a regression, but it's on undocumented behaviour and is as simple to fix as using substr (and it will work for new and ancient versions alike).

comment:9 Changed 19 months ago by longdogz

I hope I'm not breaking protocol by adding information to this bug. Please let me know if I should have entered a new bug, instead.

Just to reinforce that this isn't only happening for one person in one situation, I have an app that seems to be running into this problem. Unfortunately, the environment in which the app runs is complicated enough that I'm not entirely sure the problem is with jQuery, but here goes.

I have a web app that I am trying to get to run as an iPhone app within PhoneGap 2.1.0 using jQuery 1.7.1 and jQuery Mobile 1.1.1. If I run it in Xcode in the iOS 5.1 Simulator, it runs just fine. However, if I run it in the iOS 6 Simulator, after the first time I have logged in and then logged out, when I hit the login API again (using $.ajax()), my success callback gets called. However, the PHP login API is not hit. Note that I found that I could add a millisecond parameter of my own to the URL and that seems to have worked around the problem. :-)

Here's my $.ajax() call:

$.ajax({

type: "POST", url: base + "login?x=" + msecs, dataType: 'json', cache: false, data: formData, success: successFunc, error: errorFunc

});

Like I said, I'm not at all sure this is a problem in jQuery (as opposed to PhoneGap or the iOS 6 Simulator), but this bug does seem to be very applicable.

comment:11 Changed 19 months ago by mikesherov

dmethvin, clearly an apple bug. There are workarounds though involving sent headers that if apple doesn't fix this bug, we can. Just wish there was more clarity into whether apple acknowledges this as a bug.

comment:12 Changed 18 months ago by jaubourg

  • Status changed from assigned to closed
  • Resolution set to fixed

Uses an additive approach to generating anti-cache parameters rather than a timestamp. Fixes #12550

Changeset: 8bae5e19af30208a25ea357921f46845f6793951

Please follow the  bug reporting guidlines and use  jsFiddle when providing test cases and demonstrations instead of pasting the code in the ticket.

View

Add a comment

Modify Ticket

Action
as closed
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.