Jun 16, 2012, 3:39 PM
[OPEN] [#129] Can Ajax requests send If-Modified-Since headers
Hi,
I've been struggling on this one for a bit. I have a store with an HttpProxy pointing to an ashx.
In the ASHX I am actually able to cache quite aggressively:
To explain further how scenario 3) would normally work, I would write something like this:
There is one way I can think of it to manually send this header:
1) Knowing what the If-Modified-Since value was is difficult to know, unless I send it as part of the response body (e.g. by subclassing Paging<T> to have that property in it).
2) Even with the subclass approach it then that means in JavaScript I need to cache the responses for each variation of the request (because I can vary the cache by numerous Store parameters such as paging, pagin size, sort, etc). I'd be trying to re-implement what browsers already do transparently...
(Also, when I do try this, I finally get the server to return a 304, but I then see the Request Failure window popup showing status 304 and Not modified. So even if I do get this to work, is the AJAX response handler only looking for statuses of 200?)
Am I missing a trick on how to do this?
Let me know if you need a reproducible example. This is in Ext.NET v1 btw; I've not had the time to try it in v2 yet...
I've been struggling on this one for a bit. I have a store with an HttpProxy pointing to an ashx.
In the ASHX I am actually able to cache quite aggressively:
context.Response.Cache.SetExpires(DateTime.Now.AddHours(10d));
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetValidUntilExpires(true);
context.Response.Cache.SetLastModified(lastModified); // <!-- I am able to get this value from my system
context.Response.Cache.VaryByHeaders["Accept-Language"] = true;
context.Response.Cache.VaryByParams["id"] = true;
context.Response.Cache.VaryByParams["dir"] = true;
context.Response.Cache.VaryByParams["limit"] = true;
context.Response.Cache.VaryByParams["sort"] = true;
context.Response.Cache.VaryByParams["start"] = true;
context.Response.Write(JSON.Serialize(pagingData));
You will see that I use a 2-pronged approach in my caching:- I can tell the browser to cache the response (e.g. 10 hours in the above)
- Before 10 hours, if the exact same request is made (same parameters and same language) within that time, the browser won't bother making an http request (it just works under the hoods by the browser which returns the cached response from earlier)
- After 10 hours the browser will request the server. The request should ideally include the If-Modified-Since header (because it was set in the above code). This gives the server a chance to say there have been no modifications since the last modified time (10 hours ago, or even before) and this means the server doesn't have to send back any data (or request it from the back end), so it becomes a really short http response and the browser just fetches the previously cached request from its own internal cache and gives it back to the underlying XHR object - in other words it should be transparent.
To explain further how scenario 3) would normally work, I would write something like this:
if (IsClientCached(lastModified, context))
{
context.Response.StatusCode = 304;
context.Response.SuppressContent = true;
context.Response.StatusDescription = "Not Modified";
context.Response.AddHeader("Content-Length", "0");
return;
}
Where IsClientCached is determined like this:private bool IsClientCached(DateTime contentModified, HttpContext context)
{
string header = context.Request.Headers["If-Modified-Since"];
if (header != null)
{
DateTime isModifiedSince;
if (DateTime.TryParse(header, out isModifiedSince))
{
return isModifiedSince > contentModified;
}
}
return false;
}
However, for scenario 3) when I look in firebug, I don't see the If-Modified-Since header being sent as part of the Store/Proxy's http request and so the server ends up getting and returning all the data again which it may not have needed to do.There is one way I can think of it to manually send this header:
<ext:Store ID="ImagesStore" runat="server" AutoLoad="false" RemoteSort="true">
<Proxy>
<ext:HttpProxy Method="GET" Url="GetImages.ashx" DisableCaching="false">
<Listeners>
<BeforeLoad Handler="if (#{ImagesStore}.reader.jsonData) {
this.conn.headers = Ext.apply({}, { 'If-Modified-Since' : /* get the value somehow */ }, this.conn.headers);
}" />
</Listeners>
</ext:HttpProxy>
</Proxy>
<!-- etc -->
</ext:Store>
However, there are two problems with the above:1) Knowing what the If-Modified-Since value was is difficult to know, unless I send it as part of the response body (e.g. by subclassing Paging<T> to have that property in it).
2) Even with the subclass approach it then that means in JavaScript I need to cache the responses for each variation of the request (because I can vary the cache by numerous Store parameters such as paging, pagin size, sort, etc). I'd be trying to re-implement what browsers already do transparently...
(Also, when I do try this, I finally get the server to return a 304, but I then see the Request Failure window popup showing status 304 and Not modified. So even if I do get this to work, is the AJAX response handler only looking for statuses of 200?)
Am I missing a trick on how to do this?
Let me know if you need a reproducible example. This is in Ext.NET v1 btw; I've not had the time to try it in v2 yet...
Last edited by Daniil; Jan 18, 2013 at 4:27 AM.
Reason: [OPEN] [#129]