Firefox 3 not using cache when ajax call made during page load - javascript

I get some json data with ajax when the page DOM is loaded using jQuery like this:
$(document).ready(function(){
getData();
});
...where getData() is a simple jQuery ajax call, something like this:
function getData(){
$.ajax({cache: true, dataType: 'json', url: '/foo/bar'});
}
The Expires header for this request is set to some time in the future, so the next time I load the page, the ajax call should use the cached data. Firefox 3 does not.
But, if I instead ask for the data like this:
$(document).ready(function(){
setTimeout("getData()", 1);
});
Firefox does respect the Expires header, and uses the cache. Any ideas why this would be?
This page mentions that browsers may treat ajax calls that occur when a page loads differently from ajax calls that occur in response to a user UI event.
Edit: I forgot to include the http headers in my original post. I think the headers are fine, because the caching works as long as the request isn't made in an ajax call when the page loads. If I visit the url that the ajax call uses in my browser URL bar, caching works, and as I explain above, caching works if I add a little delay to the ajax call.
Request headers
Host 10.0.45.64:5004
User-Agent Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9
Accept application/json, text/javascript, /
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
X-Requested-With XMLHttpRequest
Cookie
Response headers
I set the Expires header to 1 week in the future so that users only need to refresh once a week.
Date Wed, 04 May 2011 15:32:04 GMT
Last-Modified Wed, 04 May 2011 15:32:03 GMT
Expires Wed, 11 May 2011 15:32:03 GMT
Content-Type text/javascript
Cache-Control Public
Connection close

Define an error handler in the $.ajax() call and inspect the response headers (using jqXHR.getAllResponseHeaders() where jqXHR is the jQuery Ajax object, status code, and responseText.length. You may find that the request is successful, but jQuery treats them as unsuccessful. I've recently had a similar issue with cached files and $.ajax(), and it turns out that sometimes when files are loaded when the browser is offline, or from a local file, return a status code of 0. Because the status doesn't fall in the range of success codes (200-300), jQuery considers the request to have failed. See this for what I did to fix this issue. Basically, in your error handler, you can check the responseText.length. If it is non-empty, consider the request successful and parse the JSON using JSON.parse(). BUT!!! you have to make sure on your server-side that invalid requests are empty.

Related

Set-Cookie in response header is not saved into browser cookie storage

the response header is
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, x-request, Content-Type, Accept
Access-Control-Allow-Origin:*
Cache-Control:private
Connection:close
Content-Length:100
Content-Type:application/json; charset=utf-8
Date:Tue, 14 Feb 2017 02:45:56 GMT
Server:nginx/1.2.8
Set-Cookie:USER=6ae633831f39447688892e6b2b156cec; Max-Age=604800; Path=/
Set-Cookie:USERINFO=298967; Max-Age=604800; Path=/
X-Powered-By:node.js
X-Ua-Compatible:chrome=1
the cookie format's right (used cookie package to serialize ). the server is developed by node.js.
not only chrome, Firefox doesn't work too. the document.cookie is empty and also i can't see cookie in application section of chrome developer tool.
Any wrong in response header ?? Please help .
This problem occur due to multiple responses from server to client.
For example if you are sending a response to the server using response.send() and same time using
you are using response.setHeader()
This problem can be solve by creating cookie in client side using javascript.
And reading its value from node.js
The answer is because i used fetch() API that have to pass {credentials => 'same-origin'} option.

Web Browser Does Not Set cookie on an Ajax Call

I'm very confused. I've got an AJAX call which causes a login form to be processed, and creates a cookie on a successful login. The web browser is not registering the cookie.
In troubleshooting, I isolated it down to something to do with the AJAX calling the site, rather than navigating directly.
e.g. I created a simple page "test" which returns the following output:
HTTP/1.1 200 OK
X-Powered-By: Express
Set-Cookie: token=ABCDEFG; Domain=localhost; Path=/
Content-Type: application/json; charset=utf-8
Content-Length: 19
ETag: W/"13-S4werj8PuppRlonJZs+jKA"
Date: Wed, 23 Sep 2015 22:09:03 GMT
Connection: keep-alive
{"message":"value"}
If I navigate directly to the page, the cookie is created in the browser.
If I make an AJAX call to the page, the cookie is not created in the browser.
e.g:
$.get('http://localhost:8081/test');
I've found similar posts which state that this happens with AJAX if the domain or the path are not defined, but as you can see, I defined these and still no dice.
If it matters, the majority of my testing has been on Firefox, but I did do at least a couple of tests on Chrome.
Any help you have would greatly be appreciated. I'm confused by this, as everything I read suggests this should be possible.
To clarify further:
1) I'm not seeing the cookie created when reviewing CookieManager+ addon for Firefox.
2) I'm also not seeing the cookie added to subsequent requests to the same host (even the same port).
3) What I read seems to suggest that cookies are tied to a host, not a port (But that doesn't seem to be the issue based on #1 and #2):
Are HTTP cookies port specific?
Try setting withCredentials in your request:
$.get('http://localhost:8081/test', {xhrFields: {withCredentials: true}});
Alternatively try setting the crossDomain value:
$.ajax({type:"GET", url:"localhost:8081/test", crossDomain:true});
If you're trying to do this in Angular, as I was, this is how you do it there:
$http doesn't send cookie in Requests
config(function ($httpProvider) {
$httpProvider.defaults.withCredentials = true;

Safari on iOS involving stale $http.get results

I've just noticed that Safari on iOS keeps stale $http.get results in cache, that target my server (REST call).
However, Safari claims a status 200 (not 304), even if result is stale... troubling
I confirm that the issue comes from Safari since it's easy to check the real result through a rest call to the server.
What I do to force Safari to refresh its cache is adding a random parameter:
$http.get('myUrl?rnd=' + new Date().getTime())
Is there a better practice? Probably changing the response headers on the server directly?
My server returns this response header:
HTTP/1.1 200 OK
Server: Cowboy
Date: Tue, 11 Nov 2014 23:52:59 GMT
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Length: 495
Via: 1.1 vegur
Your response doesn't have any cache control headers. According to this answer browsers are free to do whatever they want if there are no cache control headers. In your case Safari on iOS has decided to cache the content even though that isn't what you want.
You could keep using your workaround, or you could add cache control headers in the response to tell Safari not to cache your response.
Note that RFC's might say that responses should not be cached if there are no cache control headers. (I haven't checked). But browsers often have non-standard behavior that you have to work around.
As an aside - early on in my computer networking job I thought that it was OK to not support browsers and webservers that didn't follow the RFCs. I was wrong.

intercept response header with jquery ajax request

Exactly what the title suggests:
I perform an ajax request to my server, it responds with a 403 but there are headers I want to retrieve and save on localStorage. This is for a phonegap app (Android and iOS), so the initiating domain isLocal (file://). When performing the call, I use the following code to try to intercept the response, but it returns undefined or an empty string.
Ajax:
$.ajax({
url: serverLink+action,
type: "POST",
data: "access_token="+accessToken+"&uid="+uid,
crossDomain: true,
complete: function(resp){
var header = resp.getAllResponseHeaders();
var match = header.match(/(Set-Cookie|set-cookie): (.+?);/);
if (match) session = match[2];
console.log(header, session)
}
})
Response Headers
Connection Keep-Alive
Content-Encoding gzip
Content-Length 1198
Content-Type text/html
Date Fri, 13 Apr 2012 22:51:02 GMT
Keep-Alive timeout=15, max=100
Server Apache/2.2.14 (Ubuntu)
Set-Cookie sessionid=ebd26167e32bada2d2ed0bd3cc16d8a2; expires=Fri, 27-Apr-2012 22:51:02 GMT; Max-Age=1209600; Path=/
Vary Cookie,Accept-Encoding
Further reading led me to here, which speaks of the CSRF on a django server. We are using a django server and either this or the 403 is the problem I suspect. There doesn't seem to be a way (from the example answer there) to collect the cookie from webview and send it back to the server on subsequent requests.
use the jquery XHR object which as a method getAllResponseHeaders() which should provide what you are after.
http://api.jquery.com/jQuery.ajax/
This problem was most definitely caused by CSRF protection on the django server. Disabling or implementing workarounds as per django is the only way around this.
Actually this post helped tremendously: Django CSRF check failing with an Ajax POST request

Difference between AJAX request and a regular browser request

Is there a difference between an AJAX request and a direct browser request (in terms of how a web page is called and loaded)?
In other words, I mean: is a direct server-side request handled in any way differently than a client-side request (initiated by the browser)?
There may be some header differences, but the main behavior difference is on the client.
When the browser makes a regular request as in window.location.href = "index.html", it clears the current window and loads the server response into the window.
With an ajax request, the current window/document is unaffected and javascript code can examine the results of the request and do what it wants to with those results (insert HTML dynamically into the page, parse JSON and use it the page logic, parse XML, etc...).
The server doesn't do anything different - it's just in how the client treats the response from the two requests.
An AJAX request is identical to a "normal" browser request as far as the server is concerned other than potentially slightly different HTTP headers. e.g. chrome sends:
X-Requested-With:XMLHttpRequest
I'm not sure if that header is standardized or not, or if it's different in every browser or even included at all in every browser.
edit: I take that back, that header is sent by jQuery (and likely other JS libraries), not the browser as is evidenced by:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/');
xhr.send();
which sends:
Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie: ....
Host:stackoverflow.com
If-Modified-Since:Sat, 31 Dec 2011 01:57:24 GMT
Referer:http://stackoverflow.com/questions/8685750/how-does-an-ajax-request-differ-from-a-normal-browser-request/8685758
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11
which leads me to the conclusion that by default there is absolutely no difference.
Some popular client-side libraries like jQuery include the X-Requested-With header in their requests and set it to XMLHttpRequest to mark them as AJAX.
This seems to have been considered standard enough a few years ago (probably due to the huge popularity of jQuery and its presence in almost every website) that many server-side frameworks even have helpers that take care of checking for this header in the received request for you:
ASP.NET MVC 5:
HttpRequestBase.IsAjaxRequest()
Django:
HttpRequest.is_ajax()
Flask:
flask.Request.is_xhr
However, it seems that with the end of jQuery's reign in the front end world and the standardization of the fetch API and the rise of other modern client-side libraries that don't add any header for this purpose by default, the pattern has fallen into obsolescence also in the backend; with ASP.NET MVC not including the helper in newer versions and Flask marking it as deprecated.
Not really. Except that most Ajax clients send a X-Requested-With=XMLHttpRequest HTTP header
I always check if "text/html" is the request's "best" Accept mimetype, because browsers always send that as the first.
Firefox example:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Of course, this may still be a ajax request with text/html as the Accept mimetype, but I found this to be reliable when you know what client will consume your backend api.
An AJAX request in Blink and Gecko-powered browsers (Firefox, Chrome, Edge etc) will send this header with AJAX requests:
Sec-Fetch-Dest: empty
That means that:
The destination is the empty string. This is used for destinations that do not have their own value. For example fetch(), navigator.sendBeacon(), EventSource, XMLHttpRequest, WebSocket, etc.
Safari does not send this header at the time of writing (and IE never has and never will, but it's only a few months before IE should be completely irrelevant).
your user-agent, aka browser, sends an XHR header which you can catch from php like this:
$_SERVER['HTTP_X_REQUESTED_WITH']

Categories