RFC 7231 § 3.4: Content negotiation

This week at the HTTP reading group we discussed content negotiation (RFC 7231 § 3.4).

We already familiar with the idea of proactive negotiation (§ 3.4.1)—where the client sends an Accepts, Accept-Language, etc. header and the server responds with the correct representation—but reactive negotiation (§ 3.4.2) was new to us, especially the idea of sending a 300 (Multiple Choices) response with a list of possible representations and letting the user (or UA) decide.

It seems like this would be more useful if there was a standard way of sending the list of alternatives, so that the UA could pick one based on the user’s preferences. We talked about using HTML that looked something like this, but without built-in browser support it would still require user interaction:

<a href="en.html" rel="alternate" hreflang="en" type="text/html">HTML, English</a>
<a href="fr.json" rel="alternate" hreflang="fr" type="application/json">JSON, French</a>

There is an experimental RFC from 1998 (RFC 2295) that defines an Alternates headers that can be used to list the options in a 300 response, but according to a W3C HTTP Working Group mailing list post from 2009 it isn’t widely supported.

Has anyone seen a 300 in the wild, or used one in their own applications?

/cc @calleerlandsson @joelq @DeviousDuck

Reactive negotiation seems like it might mitigate some privacy concerns; namely, with proactive negotiation, the UA must send detailed information each time, typically the same (e.g. User-Agent). With reactive, the User-Agent can be more slim and the user can choose what information to send.

Reactive negotiation would also make caching easier, because—if I’m reading the spec correctly—all of the alternate representations would have unique URIs, whereas proactive negotiation requires the Vary header to be set correctly.

We did some experiments at the reading group, and a Rails resource with multiple formats will pick the right one based on the Accept header, but it won’t set Vary: Accept so a cache could return the wrong content type (we weren’t sure if the Content-Type response header should be included in the cache key, but according to RFC 7234 § 2 the primary cache key “consists of the request method and target URI” and any secondary key is based on the request headers listed in the Vary response header).