Negoziazione del contenuto

Traduzione in corso.

In HTTP, content negotiation is the mechanism that is used for serving different representations of a resource at the same URI, so that the user agent can specify which is best suited for the user (for example, which language of a document, which image format, or which content encoding).

Nel protocollo HTTP, la negoziazione del contenuto è il meccanismo utilizzato per servire diverse rappresentazioni di una risorsa avente medesimo URI, in modo che il programma utente possa specificare quale sia più adatta all'utente (ad esempio, quale lingua di un documento, quale formato immagine o quale codifica del contenuto).

Nota: alcuni svantaggi della negoziazione del contenuto HTTP sono spiegati in una pagina wiki del WHATWG. HTML5 fornisce alternative alla negoziazione del contenuto tramite, ad esempio, l'elemento <source>.

Principi di negoziazione dei contenuti

Uno specifico documento è chiamato risorsa. Quando un client desidera ottenere una risorsa, il client la richiede utilizzando il suo URL. Il server utilizza questo URL per scegliere una delle varianti che fornisce - ogni variante viene chiamata rappresentazione - e restituisce una rappresentazione specifica per il client. La risorsa complessiva, così come ciascuna delle rappresentazioni, ha un URL specifico. Il modo in cui viene scelta una rappresentazione specifica quando la risorsa viene chiamata è determinato dalla negoziazione del contenuto e ci sono diversi modi per negoziare tra il client e il server.

La determinazione della rappresentazione più adatta avviene attraverso uno dei seguenti meccanismi:

  • Intestazioni HTTP specifiche da parte del client (negoziazione guidata dal server o negoziazione proattiva), che è il modo standard di negoziare un tipo specifico di risorsa.
  • La restituzione dei codici di risposta HTTP 300 (Multiple Choices) o 406 (Not Acceptable) dal server (negoziazione guidata dall'agente o negoziazione reattiva), utilizzati come meccanismi di riserva.

Nel corso degli anni sono state avanzate altre proposte di negoziazione dei contenuti, come la negoziazione trasparente dei contenuti e l'intestazione Alternates, ma non hanno ottenuto la giusta attenzione e sono state quindi abbandonate.

Negoziazione dei contenuti gestita dal server

Nella negoziazione del contenuto gestita lato server, o negoziazione proattiva del contenuto, il browser (o qualsiasi altro tipo di user-agent) invia diverse intestazioni HTTP insieme all'URL. Queste intestazioni descrivono la scelta preferita dell'utente. Il server li utilizza come suggerimenti e un algoritmo interno sceglie il contenuto migliore da offrire al client. L'algoritmo è specifico del server e non è definito dallo standard. Vedi, ad esempio, l'algoritmo di negoziazione di Apache.

Lo standard HTTP / 1.1 definisce l'elenco delle intestazioni standard che avviano la negoziazione guidata dal server (Accept, Accept-Charset, Accept-Encoding, Accept-Language). Sebbene in senso stretto User-Agent non sia in questo elenco, a volte viene anche utilizzato per inviare una rappresentazione specifica della risorsa richiesta, per quanto questa non sia considerata una buona pratica. Il server utilizza l'intestazione Vary per indicare quali intestazioni ha effettivamente utilizzato per la negoziazione del contenuto (o più precisamente le intestazioni di risposta associate), in modo che le cache possano funzionare in modo ottimale.

Oltre a questi, c'è una proposta sperimentale per aggiungere più intestazioni all'elenco delle intestazioni disponibili, chiamate suggerimenti del client. I suggerimenti del client indicano il tipo di dispositivo su cui viene eseguito l'user agent (ad esempio, se si tratta di un computer desktop o di un dispositivo mobile).

Anche se la negoziazione del contenuto guidata dal server è il modo più comune per concordare una rappresentazione specifica di una risorsa, presenta diversi svantaggi:

  • Il server non ha una conoscenza totale del browser. Anche con l'estensione dei suggerimenti del client, non ha una conoscenza completa delle capacità del browser. A differenza della negoziazione del contenuto reattivo in cui il client fa la scelta, la scelta del server è sempre piuttosto arbitraria;
  • Le informazioni fornite dal client sono piuttosto dettagliate (la compressione dell'intestazione HTTP / 2 mitiga questo problema) e un rischio per la privacy (impronta digitale HTTP);
  • Poiché vengono inviate diverse rappresentazioni di una determinata risorsa, le cache condivise sono meno efficienti e le implementazioni del server sono più complesse.

The Accept header

The Accept header lists the MIME types of media resources that the agent is willing to process. It is comma-separated lists of MIME types, each combined with a quality factor, a parameter indicating the relative degree of preference between the different MIME types.

The Accept header is defined by the browser, or any other user-agent, and can vary according to the context, like fetching an HTML page or an image, a video, or a script: It is different when fetching a document entered in the address bar or an element linked via an <img>, <video> or <audio> element. Browsers are free to use the value of the header that they think is the most adequate; an exhaustive list of default values for common browsers is available.

The Accept-CH header

This is part of an experimental technology called Client Hints. Initial support is in Chrome 46 or later. The Device-Memory value is in Chrome 61 or later.

The experimental Accept-CH lists configuration data that can be used by the server to select an appropriate response. Valid values are:

Value Meaning
Device-Memory Indicates the approximate amount of device RAM. This value is an approximation given by rounding to the nearest power of 2 and dividing that number by 1024. For example, 512 megabytes will be reported as 0.5.
DPR Indicates the client's device pixel ratio.
Viewport-Width Indicates the layout viewport width in CSS pixels.
Width Indicates the resource width in physical pixels (in other words the intrinsic size of an image).

The Accept-Charset header

The Accept-Charset header indicates to the server what kinds of character encodings are understood by the user-agent. Traditionally, it was set to a different value for each locale for the browser, like ISO-8859-1,utf-8;q=0.7,*;q=0.7 for a Western European locale.

With UTF-8 now being well-supported, being the preferred way of encoding characters, and to guarantee better privacy through less configuration-based entropy, browsers omit the Accept-Charset header: Internet Explorer 8, Safari 5, Opera 11, Firefox 10 and Chrome 27 have abandoned this header.

The Accept-CH-Lifetime header

This is part of an experimental technology called Client Hints and is only available in Chrome 61 or later.

The Accept-CH-Lifetime header is used with the Device-Memory value of the Accept-CH header and indicates the amount of time the device should opt-in to sharing the amount of device memory with the server. The value is given in miliseconds and it's use is optional.

The Accept-Encoding header

The Accept-Encoding header defines the acceptable content-encoding (supported compressions). The value is a q-factor list (e.g.: br, gzip;q=0.8) that indicates the priority of the encoding values. The default value identity is at the lowest priority (unless otherwise declared).

Compressing HTTP messages is one of the most important ways to improve the performance of a Web site, it shrinks the size of the data transmitted and makes better use of the available bandwidth; browsers always send this header and the server should be configured to abide to it and to use compression.

The Accept-Language header

The Accept-Language header is used to indicate the language preference of the user. It is a list of values with quality factors (like: "de, en;q=0.7"). A default value is often set according the language of the graphical interface of the user agent, but most browsers allow to set different language preferences.

Due to the configuration-based entropy increase, a modified value can be used to fingerprint the user, it is not recommended to change it and a Web site cannot trust this value to reflect the actual wish of the user. Site designers must not be over-zealous by using language detection via this header as it can lead to a poor user experience:

  • They should always provide a way to overcome the server-chosen language, e.g., by providing a language menu on the site. Most user-agents provide a default value for the Accept-Language header, adapted to the user interface language and end users often do not modify it, either by not knowing how, or by not being able to do it, as in an Internet café for instance.
  • Once a user has overridden the server-chosen language, a site should no longer use language detection and should stick with the explicitly-chosen language. In other words, only entry pages of a site should select the proper language using this header.

The User-Agent header

Though there are legitimate uses of this header for selecting content, it is considered bad practice to rely on it to define what features are supported by the user agent.

The User-Agent header identifies the browser sending the request. This string may contain a space-separated list of product tokens and comments.

A product token is a name followed by a '/' and a version number, like Firefox/4.0.1. There may be as many of them as the user-agent wants. A comment is a free string delimited by parentheses. Obviously parentheses cannot be used in that string. The inner format of a comment is not defined by the standard, though several browser put several tokens in it, separated by ';'.

The Vary response header

In opposition to the previous Accept-* headers which are sent by the client, the Vary HTTP header is sent by the web server in its response. It indicates the list of headers used by the server during the server-driven content negotiation phase. The header is needed in order to inform the cache of the decision criteria so that it can reproduce it, allowing the cache to be functional while preventing serving erroneous content to the user.

The special value of '*' means that the server-driven content negotiation also uses information not conveyed in a header to choose the appropriate content.

The Vary header was added in the version 1.1 of HTTP and is necessary in order to allow caches to work appropriately. A cache, in order to work with server-driven content negotiation, needs to know which criteria was used by the server to select the transmitted content. That way, the cache can replay the algorithm and will be able to serve acceptable content directly, without more request to the server. Obviously, the wildcard '*' prevents caching from occurring, as the cache cannot know what element is behind it.

Agent-driven negotiation

Server-driven negotiation suffers from a few downsides: it doesn't scale well. There is one header per feature used in the negotiation. If you want to use screen size, resolution or other dimensions, a new HTTP header must be created. Sending of the headers must be done on every request. This is not too problematic with few headers, but with the eventual multiplications of them, the message size would lead to a decrease in performance. The more precise headers are sent, the more entropy is sent, allowing for more HTTP fingerprinting and corresponding privacy concern.

From the beginnings of HTTP, the protocol allowed another negotiation type: agent-driven negotiation or reactive negotiation. In this negotiation, when facing an ambiguous request, the server sends back a page containing links to the available alternative resources. The user is presented the resources and choose the one to use.

Unfortunately, the HTTP standard does not specify the format of the page allowing to choose between the available resource, which prevents to easily automatize the process. Besides falling back to the server-driven negotiation, this method is almost always used in conjunction with scripting, especially with JavaScript redirection: after having checked for the negotiation criteria, the script performs the redirection. A second problem is that one more request is needed in order to fetch the real resource, slowing the availability of the resource to the user.