2
votes

No matter what I do I can't get images returned from a web api too cache, I am seeing a request to the server every time I request the image.

I have tried many permiations for the header setting, here is my latest effort:

  public class TestController : ApiController
    {
        public HttpResponseMessage Get(int id)
        {
            HttpResponseMessage response = new HttpResponseMessage();

            StreamContent streamContent = new StreamContent(File.Open("c:\\1.jpg", FileMode.Open, FileAccess.Read, FileShare.Read));
                    
            response.Content = streamContent;
            response.Content.Headers.Add("Content-Type", "image/jpeg");
            response.Headers.CacheControl = new CacheControlHeaderValue
            {
                MustRevalidate = true,
                Private= false,
                MaxAge = TimeSpan.FromMinutes(1),
            };

            //string hash = new Guid("524DF956-D67A-4D66-A3E0-5E78726A204A").GetHashCode().ToString();
            //response.Headers.ETag = new EntityTagHeaderValue(String.Concat("\"", hash, "\""), true);
            //response.Content.Headers.LastModified = new DateTimeOffset(new DateTime(2012, 12, 24));
            //response.Content.Headers.Expires = new DateTimeOffset(new DateTime(2013, 12, 24));
            return response;
        }

And this is what the response headers look like when I inspect with chrome:

Cache-Control:must-revalidate, max-age=60 Content-Length:24233

Content-Type:image/jpeg Date:Sun, 14 Apr 2013 22:04:32 GMT

Server:Microsoft-IIS/8.0 X-AspNet-Version:4.0.30319

X-Powered-By:ASP.NET

X-SourceFiles:=?UTF-8?B?Qzpcc291cmNlXFRydW5rXFRlc3RcYXBpXHRlc3RcMQ==?=

Any ideas on how to proceed?

2

2 Answers

2
votes

If you're looking for a 200 / 304 situation, then probably the biggest step you're missing at this stage, is that your server code needs to choose when to return a 304, vs a 200 with full message body. When the conditions of your cache rules are met (and you'll need to decide what those are), then you'll want:

return new HttpResponseMessage(HttpStatusCode.NotModified); // 304

Part2:

The next choice then, is deciding on your cache rule. Your current code won't get any further than the first step of cache check (if even that). You need to return a LastModified and / or ETag for the client to then use in subsequent requests to perform a cache check.

LastModified is fairly straight-forward. Compare the dates, if the resource has been modified since the LastModified date, then return a full response, othrwise, 304.

ETag should uniquely represent the resource, not the request (as your current commented out ETag code would be doing). A hash may make sense for an ETag, but only if it's a hash of the resource you're returning, not if it's a completely unique hash each time. Think of it like a timestamp, or version number even. Client gets version 1 of an image, with an ETag value of (hypothetically) "1". Client then sends a request for that image including the ETag value, the server then checks if "1" is still the valid version and returns 200 + body + new ETag or 304 as appropriate.

0
votes

You should put Private=true if you want the browser to be able to cache your content and public=true if you want shared caches to cache it.