HTTP / 2 rende obsoleti i websocket?


290

Sto imparando a conoscere il protocollo HTTP / 2. È un protocollo binario con piccoli frame di messaggi. Consente il multiplexing del flusso su una singola connessione TCP. Concettualmente sembra molto simile a WebSocket.

Sono previsti websocket obsoleti e sostituirli con una sorta di richieste HTTP / 2 senza intestazione e messaggi push avviati dal server? O WebSocket completerà HTTP / 2?


Penso che la risposta accettata sia corretta, i websocket sono ancora la soluzione preferita per le applicazioni web per comunicare con il server in modo bidirezionale, inclusi i messaggi inviati dal server. HTTP viene utilizzato non solo per i browser e quando sia il client che il server possono utilizzare API di basso livello, non hanno bisogno di websocket. Tuttavia, la maggior parte delle persone utilizza HTTP per le applicazioni Web e si preoccupa principalmente delle API esposte a JavaScript. Se i moderatori pensano che la risposta accettata debba essere diversa, non sono contrario poiché questa domanda apparentemente genera molte opinioni e la mia opinione potrebbe essere sbagliata.
vbezhenar

Risposte:


170

Da quello che ho capito, HTTP / 2 non è un sostituto per websocket ma mira a standardizzare il protocollo SPDY.

In HTTP / 2, il server push viene utilizzato dietro le quinte per migliorare il caricamento delle risorse da parte del client dal browser. Come sviluppatore, non ti interessa davvero durante il tuo sviluppo. Tuttavia, con Websocket, lo sviluppatore può utilizzare l'API che è in grado di utilizzare e inviare messaggi con una connessione full duplex univoca.

Queste non sono le stesse cose e dovrebbero completarsi a vicenda.


3
Grazie Guillaume per la tua risposta. Tuttavia mi chiedo se tu (o qualcuno) potresti aggiungere qualche riferimento dalla specifica HTTP / 2. Quello che ho letto da blog e così via - con HTTP / 2 c'è una vera comunicazione bidirezionale?
Martin Meeser

3
Non sono sicuro che la specifica HTTP / 2 sia il posto giusto per fornire dettagli sulle origini di HTTP / 2 e su come differisce da websocket. Tuttavia, puoi facilmente vedere che con HTTP / 2 stiamo usando una comunicazione bidirezionale: goo.gl/IJVxWS (pagina 6 e 13)
Guillaume D.

31
HTTP / 2 è effettivamente bidirezionale ma non simmetrico, il che significa che solo il client può inviare una richiesta appropriata e il server può inviare risposte e richiedere promesse (push). Ciò rende i websocket diversi nel senso che entrambe le parti sono più "uguali" in termini di ciò che possono inviare / ricevere.
George Antoniadis

3
C'è un eccellente podcast sulla Software Engineering Radio IEEE sulle origini di HTTP2. Penso che sia questo: se-radio.net/2015/07/episode-232-mark-nottingham-on-http2
Max Murphy

2
una risposta simile con una logica completa può essere trovata in questo articolo di InfoQ qui: infoq.com/articles/websocket-and-http2-coexist
mantrid

179

Dopo aver appena finito di leggere le specifiche HTTP / 2 , penso che HTTP / 2 abbia websocket obsoleti per la maggior parte dei casi d'uso, ma forse non tutti.

PUSH_PROMISE(colloquialmente noto come server push) non è il problema qui. Questa è solo un'ottimizzazione delle prestazioni.

Il caso d'uso principale per Websocket in un browser è abilitare lo streaming bidirezionale di dati. Quindi, penso che la domanda dell'OP sia se HTTP / 2 faccia un lavoro migliore nell'abilitare lo streaming bidirezionale nel browser, e penso che sì, lo fa.

Prima di tutto, è bi-di. Basta leggere l'introduzione alla sezione stream :

Un "flusso" è una sequenza indipendente e bidirezionale di frame scambiati tra il client e il server all'interno di una connessione HTTP / 2. Gli stream hanno diverse caratteristiche importanti:

Una singola connessione HTTP / 2 può contenere più flussi aperti contemporaneamente, con i frame che intercalano gli endpoint da più flussi.

I flussi possono essere stabiliti e utilizzati unilateralmente o condivisi dal client o dal server.

I flussi possono essere chiusi da entrambi gli endpoint.

Articoli come questo (collegati in un'altra risposta) sono sbagliati su questo aspetto di HTTP / 2. Dicono che non è bidi. Guarda, c'è una cosa che non può accadere con HTTP / 2: dopo che la connessione è stata aperta, il server non può avviare un flusso regolare, ma solo un flusso push. Ma una volta che il client apre un flusso inviando una richiesta, entrambe le parti possono inviare frame di DATI attraverso un socket persistente in qualsiasi momento - bidi completi.

Non è molto diverso dai websocket: il client deve avviare una richiesta di aggiornamento websocket prima che anche il server possa inviare dati.

La differenza più grande è che, a differenza dei websocket, HTTP / 2 definisce la propria semantica di multiplexing: come i flussi ottengono identificatori e come i frame trasportano l'id del flusso su cui si trovano. HTTP / 2 definisce anche la semantica di controllo del flusso per l'assegnazione di priorità ai flussi. Questo è importante nella maggior parte delle applicazioni del mondo reale di bidi.

(L'articolo sbagliato dice anche che lo standard Websocket ha il multiplexing. No, non è così. Non è davvero difficile scoprirlo, basta aprire Websocket RFC 6455 e premere ⌘-F, e digitare "multiplex". Dopo aver letto

Il protocollo deve essere estensibile; le versioni future probabilmente introdurranno concetti aggiuntivi come il multiplexing.

Scoprirai che esiste una bozza di estensione 2013 per il multiplexing Websocket. Ma non so quali browser, se ce ne sono, lo supportano. Non proverei a costruire la mia webapp SPA sul retro di quell'estensione, specialmente con HTTP / 2 in arrivo, il supporto potrebbe non arrivare mai).

Il multiplexing è esattamente il tipo di cosa che normalmente devi fare da solo ogni volta che apri un websocket per bidi, ad esempio, per alimentare un'app a pagina singola che si aggiorna in modo reattivo. Sono contento che sia nelle specifiche HTTP / 2, risolto una volta per tutte.

Se vuoi sapere cosa può fare HTTP / 2, guarda gRPC. gRPC è implementato su HTTP / 2. Guarda in particolare le opzioni di streaming half e full duplex offerte da gRPC. (Si noti che gRPC attualmente non funziona nei browser, ma in realtà è perché i browser (1) non espongono il frame HTTP / 2 al javascript del client e (2) generalmente non supportano i trailer, che vengono utilizzati in le specifiche gRPC.)

Dove potrebbero ancora avere un posto i websocket? Il più grande è il server-> i dati binari inviati dal browser. HTTP / 2 consente dati binari inviati dal server e dal browser, ma non è esposto nel browser JS. Per applicazioni come il push di frame audio e video, questo è un motivo per utilizzare i websocket.

Modifica: 17 gennaio 2020

Nel corso del tempo questa risposta è gradualmente salita in cima (il che è positivo, perché questa risposta è più o meno corretta). Tuttavia ci sono ancora commenti occasionali che dicono che non è corretto per vari motivi, di solito legati a qualche confusione su PUSH_PROMISEo come effettivamente consumare server orientato ai messaggi -> push client in un'app a pagina singola. E c'è un caso d'uso per i websocket in un browser, che sono dati binari inviati dal server. Per i dati testuali incluso JSON, non utilizzare websocket, usa SSE.

Ricapitolando: il protocollo HTTP / 2 è completo bi-di. Tuttavia, i browser Web moderni non espongono il protocollo HTTP / 2 orientato ai frame a JavaScript . Tuttavia, se effettui più richieste alla stessa origine su una connessione HTTP / 2, sotto il cofano tutto quel traffico viene multiplexato su una connessione (ed è quello che ci interessa!).

Quindi, se hai bisogno di creare un'app di chat in tempo reale, diciamo, dove devi trasmettere nuovi messaggi di chat a tutti i client nella chat room che hanno connessioni aperte, puoi (e probabilmente dovresti) farlo senza websocket.

Dovresti utilizzare gli eventi inviati dal server per inviare i messaggi verso il basso e l' API Fetch per inviare le richieste. Server-Sent Events (SSE) è un'API poco conosciuta ma ben supportata che espone un flusso da server a client orientato ai messaggi. Sebbene non sembri al client JavaScript, sotto il cofano il tuo browser (se supporta HTTP / 2) riutilizzerà una singola connessione TCP per multiplexare tutti quei messaggi. Non c'è perdita di efficienza e in effetti è un guadagno rispetto ai websocket. Hai bisogno di più stream? Apri più EventSource! Verranno automaticamente multiplexati per te.

Oltre ad essere più efficienti in termini di risorse e ad avere una latenza iniziale inferiore rispetto a un handshake websocket, gli eventi inviati dal server hanno la bella proprietà che si ritirano automaticamente e funzionano su HTTP / 1.1. Ma quando hai una connessione HTTP / 2 funzionano incredibilmente bene.

Ecco un buon articolo con un esempio reale di come realizzare la SPA con aggiornamento reattivo.


25
Questa risposta è parzialmente in disaccordo con le altre, inclusa quella accettata, ed è anche la migliore risposta perché si basa su fonti dirette.
sudo

7
Sono pienamente d'accordo con questa risposta e il commento. HTTP / 2 è bidirezionale basato su stream.
Martin Meeser

3
Risposta effettivamente corretta, il ragazzo si è preso la briga di controllare le fonti e l'applicazione del mondo reale (grpc)
Vladimir Akopyan

1
HTTP / 2 supporta le connessioni bidirezionali ma non significa che HTTP / 2 diventi obsoleto WebSocket. Le connessioni bidirezionali possono essere stabilite solo utilizzando i dettagli del protocollo che non devono essere esposti in Web-API. Se HTTP / 2 rende obsoleti i WebSocket, anche HTTP / 1.1 potrebbe rendere obsoleti i WebSocket. HTTP / 1.1 supporta già le connessioni bidirezionali utilizzando l' intestazione Upgrade . Questa intestazione è stata successivamente utilizzata per implementare WebSocket su HTTP / 1.1. Ora, sembra che anche i WebSocket utilizzino le capacità bidirezionali di HTTP / 2 .
JojOatXGME

4
Questa risposta è semplicemente sbagliata. Confonde così tanti aspetti da confondere facilmente. Tuttavia, il nocciolo della questione è che i flussi HTTP / 2 "bidi" sono guidati da richiesta-risposta (e in numero limitato), mentre il protocollo WebSocket è un vero protocollo bidi basato su messaggi (non è basato su richiesta-risposta, ad eccezione della fase di stretta di mano). Questa è un'enorme differenza che non può essere colmata semplicemente leggendo erroneamente le specifiche (come sembra aver fatto involontariamente @masonk).
Myst

69

Dico di no (i Websocket non sono obsoleti ).

Il primo e più spesso ignorato problema è che il push HTTP / 2 non è applicabile e potrebbe essere ignorato da proxy, router, altri intermediari o persino dal browser.

cioè (dalla bozza HTTP2):

Un intermediario può ricevere push dal server e scegliere di non inoltrarli al client . In altre parole, come utilizzare le informazioni inviate dipende da quell'intermediario. Allo stesso modo, l'intermediario potrebbe scegliere di eseguire push aggiuntivi al client, senza che sia eseguita alcuna azione dal server.

Quindi, HTTP / 2 Push non può sostituire WebSocket.

Inoltre, le connessioni HTTP / 2 si chiudono dopo un po '.

È vero che lo standard afferma che:

Le connessioni HTTP / 2 sono persistenti. Per prestazioni ottimali, ci si aspetta che i client non chiudano le connessioni fino a quando non viene determinato che non sono necessarie ulteriori comunicazioni con un server (ad esempio, quando un utente si allontana da una particolare pagina Web) o fino a quando il server non chiude la connessione.

Ma...

I server sono incoraggiati a mantenere le connessioni aperte il più a lungo possibile, ma sono autorizzati a terminare le connessioni inattive se necessario. Quando uno degli endpoint sceglie di chiudere la connessione TCP a livello di trasporto, l'endpoint di terminazione DOVREBBE prima inviare un frame GOAWAY (Sezione 6.8) in modo che entrambi gli endpoint possano determinare in modo affidabile se i frame inviati in precedenza sono stati elaborati e completare o terminare le attività rimanenti necessarie.

Anche se la stessa connessione consente di spingere il contenuto mentre è aperta e anche se HTTP / 2 risolve alcuni dei problemi di prestazioni introdotti dal "keep-alive" di HTTP / 1.1 ... le connessioni HTTP / 2 non vengono mantenute aperte a tempo indeterminato .

Né una pagina web può riavviare una connessione HTTP / 2 una volta chiusa (a meno che non siamo tornati a tirare a lungo, cioè).

EDIT (2017, due anni dopo)

Le implementazioni di HTTP / 2 mostrano che più schede / finestre del browser condividono una singola connessione HTTP / 2, il che significa che pushnon saprà mai a quale scheda / finestra appartiene, eliminando l'uso di pushcome sostituto di Websocket.

EDIT (2020)

Non sono sicuro del motivo per cui le persone hanno iniziato a votare la risposta. Semmai, gli anni trascorsi da quando la risposta è stata inizialmente pubblicata hanno dimostrato che HTTP / 2 non può sostituire WebSocket e non è stato progettato per farlo.

Certo, HTTP / 2 potrebbe essere utilizzato per eseguire il tunneling delle connessioni WebSocket, ma queste connessioni con tunnel richiederanno comunque il protocollo WebSocket e influenzeranno il modo in cui si comporta il contenitore HTTP / 2.


4
Anche i socket WS non rimarranno aperti per sempre. Le differenze sono i flussi; HTTP / 2 fornisce più flussi di flusso, il che significa che il controllo del flusso sul server è molto diverso e spesso senza blocchi. WS (come protocollo) deve avere un'elaborazione in entrata non regolamentata. Il controllo del flusso è implementato più in alto nello stack. Per la sicurezza e l'integrità del server, HTTP / 2 è molto meglio di WS.
obbligazione

4
@bond, sono d'accordo sul fatto che HTTP / 2 abbia molti vantaggi come livello di trasporto (la condivisione di una singola connessione tra molte schede del browser è solo un esempio). Tuttavia, non è progettato come livello di comunicazione . È una domanda funzionale. Entrambi i protocolli rispondono a esigenze diverse. cioè implementare un sshterminale sul browser è un gioco da ragazzi quando si utilizzano Websocket. Sarebbe un mal di testa totale su HTTP / 2, soprattutto se è aperta più di una scheda. Inoltre, cosa succede se il browser (o uno dei proxy HTTP / 2) ha chiuso la connessione? Il cliente può semplicemente presumere che non siano disponibili nuovi dati? torniamo ai sondaggi.
Myst

1
Il browser può chiudere altrettanto facilmente la connessione WS. Questa è la vita con qualsiasi tipo di rete. Ad essere onesti, il multiplexing in HTTP / 2 è eccessivo. Il protocollo non ne aveva davvero bisogno. Con l'apertura di più flussi si inizia a incontrare problemi con i buffer TCP che limitano il throughput. Sono d'accordo con te che WS è migliore in quello che fa di HTTP / 2. Fondamentalmente, WS è qualcosa che necessita di molti controlli di livello superiore per impedire agli utenti di fare cose cattive.
obbligazione

2
Per citare Zio Ben (Spider-Man): "Ricorda, da un grande potere derivano grandi responsabilità". Sì, @bond, hai ragione. Websocket, essendo un protocollo molto "grezzo", richiede una progettazione del server più responsabile. E sì, WS può essere chiuso facilmente come HTTP / 2, ma WS supporta la oncloserichiamata, quindi non è necessario alcun polling. Per quanto riguarda il multiplexing, penso sia stata una necessità piuttosto che una scelta. keep-alivefallito e l'unico modo per evitare il calo delle prestazioni "first-in-line" era rischiare il multiplexing. Il tempo lo dirà :)
Myst

1
Dal punto di vista della progettazione del server, il multiplexing in uscita è un problema complicato e costoso. Richiede che i meccanismi di I / O per eseguire il polling interno siano costosi da morire. A meno che non si stiano trasmettendo in streaming documenti di grandi dimensioni, il multiplexing non funzionerà nemmeno perché la richiesta avrà probabilmente risposto e bufferizzata completamente internamente prima che il secondo diventi disponibile e il multiplexing non venga eseguito. RTMP ha il multiplexing in uscita, ma solo il server di Adobe lo fa. È incredibile quanto sia vicino HTTP / 2 a RTMP.
obbligazione

41

La risposta è no. Gli obiettivi tra i due sono molto diversi. Esiste anche una RFC per WebSocket su HTTP / 2 che consente di effettuare più connessioni WebSocket su una singola pipe HTTP / 2 TCP.

WS su HTTP / 2 sarà un gioco di conservazione delle risorse riducendo il tempo necessario per aprire nuove connessioni e consentendo più canali di comunicazione senza la spesa aggiuntiva di più socket, IRQ soft e buffer.

https://tools.ietf.org/html/draft-hirano-httpbis-websocket-over-http2-01


È stupefacente! C'è qualche esempio pubblico di un client Javascript che lo ha implementato? Non riesco a trovare alcun esempio. Cosa dovrei fare? È una buona risorsa? undertow.io/blog/2015/04/27/An-in-depth-overview-of-HTTP2.html
RaisinBranCrunch

Qualcuno conosce una fonte delle affermazioni di cui sopra su 1) trovare la lunghezza dell'intestazione, 2) inserire in lettere minuscole i nomi dei campi?
Pim Heijden

@PimHeijden che rileva la lunghezza dell'intestazione in HTTP / 1.x richiede il loop di tutti i byte alla ricerca del marker di fine a 4 byte. È molto costoso. La mancanza di distinzione tra maiuscole e minuscole dei nomi dei campi significa anche che qualsiasi corrispondenza dei campi deve essere eseguita sia per la versione maiuscola che per quella minuscola dei caratteri. Ciò richiede la conoscenza dell'intero set di caratteri in maiuscolo e minuscolo per i controlli. In 2.x puoi presumere che siano minuscole.
obbligazione

@RaisinBranCrunch Non puoi controllare nulla di tutto questo da Javascript. Il browser fa tutto per te.
obbligazione

@bond Attualmente sto utilizzando HTTP / 2 con Nginx e proxy_pass per inviare connessioni websocket a un server socket, ma quando un singolo utente apre più schede nel sito Web, il server socket lo considera come connessioni multiple. Presumo che se HTTP / 2 esegue il multiplexing delle connessioni su un pipe TCP, il server lo tratterebbe come una connessione. È sbagliato? C'è un modo per verificare che il server non stia effettuando connessioni extra non necessarie?
RaisinBranCrunch

24

Bene, per citare da questo articolo di InfoQ :

Bene, la risposta è chiaramente no, per un semplice motivo: come abbiamo visto sopra, HTTP / 2 introduce Server Push che consente al server di inviare in modo proattivo le risorse alla cache del client. Tuttavia, non consente il push dei dati nell'applicazione client stessa. I push del server vengono elaborati solo dal browser e non vengono visualizzati nel codice dell'applicazione, il che significa che non esiste un'API per l'applicazione per ricevere notifiche per tali eventi.

E così il push HTTP2 è davvero qualcosa tra il tuo browser e il server, mentre i Websocket espongono davvero le API che possono essere utilizzate sia dal client (javascript, se è in esecuzione sul browser) che dal codice dell'applicazione (in esecuzione sul server) per il trasferimento di dati in tempo reale.


5

Lo scambio di messaggi e lo streaming semplice (non audio, streaming video) possono essere effettuati tramite multiplexing Http / 2 e WebSocket. Quindi c'è qualche sovrapposizione, ma i WebSocket hanno un protocollo ben consolidato, molti framework / API e meno overhead di intestazioni. Ecco un bell'articolo sull'argomento .


4

Ad oggi no.

HTTP / 2, rispetto a HTTP, consente di mantenere una connessione con un server. Da lì, puoi avere più flussi di dati contemporaneamente. L'intento è che puoi spingere più cose allo stesso tempo anche senza che il client lo richieda. Ad esempio, quando un browser richiede un index.html, il server potrebbe voler inviare anche index.csse index.js. Il browser non lo ha richiesto, ma il server potrebbe fornirlo senza che te lo chieda perché può presumere che lo vorrai in pochi secondi.

Questo è più veloce di HTTP / 1 alternativa di ottenere index.html, analisi, scoprendo di cui ha bisogno index.jse index.csse poi la costruzione di 2 altre richieste di quei file. HTTP / 2 consente al server di inviare dati che il client non ha nemmeno richiesto.

In quel contesto, è simile a WebSocket, ma non proprio in base alla progettazione. WebSocket dovrebbe consentire una comunicazione bidirezionale simile a una connessione TCP o una connessione seriale. È una presa in cui entrambi comunicano tra loro. Inoltre, la differenza principale è che è possibile inviare pacchetti di dati arbitrari in byte grezzi, non incapsulati nel protocollo HTTP. I concetti di intestazioni, percorsi, stringhe di query si verificano solo durante l'handshake, ma WebSocket apre un flusso di dati.

L'altra differenza è che ottieni un accesso molto più preciso a WebSocket in Javascript, mentre con HTTP, è gestito dal browser. Tutto ciò che ottieni con HTTP è tutto ciò che puoi inserire in XHR/ fetch(). Ciò significa che anche il browser si arriva a intercettare e modificare le intestazioni HTTP senza che tu sia in grado di controllarlo (ad esempio: Origin, Cookies, ecc). Inoltre, ciò che HTTP / 2 è in grado di inviare viene inviato al browser. Ciò significa che JS non sempre (se mai) sa che le cose vengono spinte. Di nuovo, ha senso per index.csse index.jsperché il browser lo memorizzerà nella cache, ma non tanto per i pacchetti di dati.

È davvero tutto nel nome. HTTP sta per HyperText Transfer Protocol. Siamo orientati al concetto di trasferimento di risorse. WebSocket riguarda la creazione di una connessione socket in cui i dati binari vengono passati in modo bidirezionale.


Quello di cui non stiamo davvero discutendo è SSE (Server-Sent Events). Il push dei dati nell'applicazione (JS) non è l'intento di HTTP / 2, ma è per SSE. SSE viene davvero rafforzato con HTTP / 2. Ma non è un vero sostituto per WebSocket quando ciò che è importante sono i dati stessi, non gli endpoint variabili che vengono raggiunti. Per ogni endpoint con WebSocket viene creato un nuovo flusso di dati, ma con SSE viene condiviso tra la sessione HTTP / 2 già esistente.


Riassunti qui sono gli obiettivi per ciascuno:

  • HTTP: risponde a una richiesta con una risorsa
  • HTTP / 2: risponde a una richiesta con più risorse
  • SSE: risponde con un flusso di eventi di testo unidirezionale (UTF-8)
  • WebSocket: crea un flusso di dati binari bidirezionale

SSE su HTTP / 2 soffre delle stesse limitazioni di HTTP1.1: un numero limitato di connessioni attive per dominio? (la limitazione è nei browser Web, circa 5 connessioni simultanee allo stesso nome host del server, quindi se hai 3 connessioni SSE dal client al tuo my-server.com, ti rimangono solo 2 connessioni per richieste HTTP regolari allo stesso mio-server.com).
Paul-Sebastian Manole,

HTTP / 2 apre idealmente una singola sessione in una connessione TCP, quindi divide quella sessione in più flussi. Il limite al numero di sessioni è generalmente visto essere 100 sui browser, sebbene possa essere deciso anche dal server. Per il sistema operativo è ancora una connessione TCP.
ShortFuse

2

Ci sarà l'implementazione di WebSocket in HTTP / 2. https://tools.ietf.org/html/rfc8441


No, non ci sarà ... la connessione WebSocket verrà sottoposta a tunnel tramite HTTP / 2, ma HTTP / 2 non sostituirà il protocollo, né diventerà obsoleto.
Myst

@ Myst L'ho detto?
Dzintars

2
No, non l'hai detto, l'ho fatto. Hai scritto che ci sarà un'implementazione di WebSocket in HTTP / 2, che IMHO sembrava troppo breve e in qualche modo fuorviante a causa dell'omissione di dettagli importanti.
Myst

2

Per il momento aprile 2020, HTTP / 2 non sta rendendo i WebSocket obsoleti. Il più grande vantaggio di WebSocket su HTTP2 è questo

HTTP/2 works only on Browser Level not Application Level

Significa che HTTP / 2 non offre alcuna API JS come WebSocket per consentire la comunicazione e trasferire un qualche tipo di JSON o altri dati al server direttamente dall'applicazione (es. Sito web). Quindi, per quanto credo, HTTP / 2 renderà WebSocket obsoleti solo se inizia a offrire API come WebSocket per parlare con il server. Fino a quando non è solo una versione aggiornata e più veloce di HTTP 1.1.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.