Anders
Anders

Reputation: 17554

Problems with Last-Modified caching

I'm doing some close to the metal HTTP tangling with Owin. I have a owin middleware that outputs javascripts. It looks like this (relevant parts)

public override Task Invoke(IOwinContext context)
{
    var response = context.Response;
    response.ContentType = "application/javascript";
    response.StatusCode = 200;

    if (ClientCached(context.Request, scriptBuildDate))
    {
        response.StatusCode = 304;
        response.Headers["Content-Length"] = "0";
        response.Body.Close();
        response.Body = Stream.Null;

        return Task.FromResult<Object>(null);
    }

    response.Headers["Last-Modified"] = scriptBuildDate.ToUniversalTime().ToString("r");
    return response.WriteAsync(js);
}

private bool ClientCached(IOwinRequest request, DateTime contentModified)
{
    string header = request.Headers["If-Modified-Since"];

    if (header != null)
    {
        DateTime isModifiedSince;
        if (DateTime.TryParse(header, out isModifiedSince))
        {
            return isModifiedSince >= contentModified;
        }
    }

    return false;
}

It will output 200 if its not client cached and add a Last-Modified date to the header, if its client cached it will output 304 "Not modified".

The problem is that the client will not call the url again unless they are doing a hard F5 in the browser. My understanding of Last modified caching is that it should call each time to check if the content has been modified?

Update:

Control: must-revalidate

F5 and ctrl+F5 will call server, opening site in new tab or restarting browser will call server, typing the address in same tab will not call server. If-Modified-Since only cleared when doing Ctrl+F5 which means it can be used to return 304 correctly when content not modified

F5 and ctrl+F5 will call server, opening site in new tab will not call server, typing the address in same tab will not call server. If-Modified-Since cleared when doing Ctrl+F5 OR when restarting browser

Cache-Control: no-cache and Pragma: no-cach

Will call server for every action If-Modified-Since only cleared when doing Ctrl+F5

Conclusion

Looks like no-cache is might better if you want to be sure it calls to check for 304 each time

Upvotes: 2

Views: 3160

Answers (1)

r3mainer
r3mainer

Reputation: 24567

From the HTTP/1.1 spec (RFC2616, my emphasis):

13.2.2 Heuristic Expiration

Since origin servers do not always provide explicit expiration times, HTTP caches typically assign heuristic expiration times, employing algorithms that use other header values (such as the Last-Modified time) to estimate a plausible expiration time. The HTTP/1.1 specification does not provide specific algorithms, but does impose worst-case constraints on their results. Since heuristic expiration times might compromise semantic transparency, they ought to used cautiously, and we encourage origin servers to provide explicit expiration times as much as possible.

Providing a Last-Modified header is not equivalent to asking user agents to check for updates every time they need a resource from your server.

Ideally, you should add an Expires header whenever possible. However, adding the header Cache-Control: must-revalidate should help.

Upvotes: 1

Related Questions