NSURLCache And The Accept Header
HTTP caching is critical to networked application on mobile devices. While tuning the various cache headers on a REST API I became interested in how NSURLCache under iOS was going to react.
This all came up because of a library that used the
Accept header to communicate the requested API version
Accept: application/json;version=1 instead of the URL path
/api/v1/…. I was initially against the idea but that sort of gut reaction is not enough. It could easily be a better approach and how would I know until I actually test my preconceptions? So, off I went to test a few things.
There are a few issues to consider about the
Accept header approach to API versioning but there was one that I couldn't even list pros and cons for. I couldn't be sure was how it would effect the cache on the client. I have worked with Varnish for HTTP caches in the past and I remembered the various
Vary header issues for internationalization.
Testing … 1 … 2 … Testing.
One quick example iOS app later and it was confirmed. A page with no
Vary header (or
Vary: *) will hit the cache no matter what
Accept header is sent. Here is the log (note the
2013-11-12 14:05:35.555 URLCacheTest[13227:70b] Requesting URL: https://abs.twimg.com/errors/twitter_web_sprite_icons.png 2013-11-12 14:05:35.556 URLCacheTest[13227:70b] Sending accept header value: api/v2 2013-11-12 14:05:35.558 URLCacheTest[13227:70b] CACHED: Non-error response code with 65084 bytes of data: 0.000851 sec 2013-11-12 14:05:39.404 URLCacheTest[13227:70b] Requesting URL: https://abs.twimg.com/errors/twitter_web_sprite_icons.png 2013-11-12 14:05:39.404 URLCacheTest[13227:70b] Sending accept header value: api/v3 2013-11-12 14:05:39.407 URLCacheTest[13227:70b] CACHED: Non-error response code with 65084 bytes of data: 0.001124 sec
I did also did an additional test of Varnish, which returns
Vary: Cookie,Accept-Encoding, and altered the
Accept-Encoding header with the same result.
NSURLCache does not take the
Accept request header into account when calculating the cache key. It would seem that it also ignores the
Vary header in the response. If you're going to use an HTTP cache in iOS for a REST API with the version in a header you're going to need to do some additional work.