when redirects improve caching

2008-04-12 @ 15:27#

i've been working on a new level of functionality for my exyus web engine this week. one of the issues i ran into has been how to create resources that are unique for a single user, but also cache-able. actually, the bigger challenge is to create *links* on pages to these user-specific resources and still make the responses that display thos links cache-able. and the solution is HTTP 302 redirects.

the challenge

here's the deal. i have a small app that uses a cookie to identify the current user. this app mints some URI for that user and then can offer up content that is specific for that user. below are some examples:

REQUEST: **************
GET /xcs/codebreaker/ HTTP/1.1

RESPONSE: **************
HTTP/1.1 200 OK
Set-Cookie: codebreaker-id=x8ca6aeb731e158a; expires=Mon, 12-May-2008 19:35:08 GMT; path=/
ETag: "dxzlW7zaqBpZrfnplRojzg"
Cache-Control: public,must-revalidate,post-check=1,pre-check=2
Content-Type: text/html; charset=utf-8
Content-Length: 2847

... html content goes here ...

so the above request/response results in an HTML document sent to the client. this document needs to have a link on it that points to this unqiue user's page (based on the cookie value generated by the server). so, you might think the HTML link would look like this:

<a href="x8ca6aeb731e158a/index.html">your page</a>

but that would be a bad thing. now this page can no longer be publicly cached. if i was using client scripting i could employ templating and do this:

<a href="{cookie:codebreakerid}/games/">your page</a>

but now the page is broken for anyone who doesn't support scripting (curl.exe, wget, mobile devices, etc.). instead, i need a link that i can use for all page that *results* in the client arriving at the unqiue URI. enter redirection.

the solution

instead of dirtying the HTML page with unique links, i can add a link that causes the client to get the proper link from the server and then go to that unique link. it could look like this:

REQUEST: **************
GET /xcs/codebreaker/games/ HTTP/1.1
Cookie: codebreaker-id=x8ca6aeb731e158a; expires=Mon, 12-May-2008 19:35:08 GMT; path=/

RESPONSE: **************
HTTP/1.1 302 Found
Location: /xcs/codebreaker/x8ca6aeb731e158a/games/
Cache-Control: private
Content-Type: text/html; charset=utf-8

now the public page has a perfectly innocent (and cache-able) link that the client can use to get to the proper location.

some caveats

first, using cookies in this way is just fine as long as you are serving up public data. this kind of cookie does not provide any security. anyone with the tools to inspect HTTP conversations can work up their own copies of cookies and mess with the web app. second, a cookie like this is client-specific and cannot be used for personalization. the same user can open up a new device (mobile, second brand of client browser, etc.) and will be granted a new unique cookie.

so there you have it. now you know how to continue to provide cache-able content while supporting unqiue URIs.