TLDR: ETags have quotes, escape them when issuing requests.

I’ve been using HTTPie to test some conditional caching I’ve been setting up on a JSON API. It’s much more intuitive than Curl, very recommended.

A funny thing about ETags is the values are surrounded by quote marks, unlike most other string-based HTTP header values. (And even better, this being the web, there’s much flexibility in implementations, even if the quotes are required by the standard.) So a response looks like:

HTTP/1.1 200 OK
...
ETag: "avm3pvp34vpoktcbd18db4c"
Normal-Header: some value

Having added conditional caching support on the server, I was now looking forward to reaping the reward and seeing 304s show up client-side. Hustling for the cacheworthy 304 Not Modified response, I tried this:

http -phH localhost:3000 If-None-Match:avm3pvp34vpoktcbd18db4c (Wrong!)

And I kept getting 200s, meaning a fresh response every time. Server wasn’t recognising the value because quotes. So the correct thing to do is:

http -phH localhost:3000 If-None-Match:”avm3pvp34vpoktcbd18db4c”

And now the server recognises it as the same ETag. Satisfying 304 is Satisfying.

(Of course, this was working all along in the browser. I figured it might be working because of the other conditional caching mechanism - timestamps (Last-Modified and If-Modified-Since headers) - even though the ETags were apparently different. But it turned out the ETags were indeed right as the browser, unlike me on the command-line, knew how to actually send them.)