Salta al contenuto
Note per Studenti Architettura delle applicazioni web - browser, server web e livelli

Architettura delle applicazioni web - browser, server web e livelli

In questa pagina 9

Una applicazione web è un programma che gli utenti usano da un browser e che vive in parte sul loro computer, in parte su una o più macchine remote. Questa nota descrive come sono divise le responsabilità (client, server, livelli), che cosa fa un browser quando riceve una pagina e come si è evoluto il web fino a oggi. Le note successive sono sui linguaggi del lato client: Linguaggi di markup - SGML, HTML e XMLUn linguaggio di markup aggiunge al testo marcatori che ne descrivono la struttura. SGML (ISO 8879, 1986) è il metalinguaggio da cui derivano HTML fino alla 4.01 e XML 1.0 (W3C, 1998, un sottoinsieme semplificato); HTML5 ha un proprio algoritmo di parsing, tollerante, e non è né SGML né XML. Un documento XML è ben formato se rispetta la sintassi (un'unica radice, tag annidati e chiusi, attributi tra virgolette, nomi con maiuscole e minuscole distinte, entità per i caratteri speciali) ed è valido se in più rispetta uno schema. La DTD dichiara elementi (ELEMENT: EMPTY, ANY, #PCDATA, sequenza con la virgola, scelta con |, cardinalità ? * +) e attributi (ATTLIST: CDATA, ID, IDREF, enumerazioni; #REQUIRED, #IMPLIED, #FIXED); non ha tipi di dato e non conosce i namespace. XML Schema (XSD) è scritto in XML e ha tipi (xs:date, xs:positiveInteger), restrizioni con pattern, minOccurs e maxOccurs, key e keyref. I namespace (xmlns, xmlns:prefisso) identificano il vocabolario con un URI; gli attributi senza prefisso non appartengono a nessun namespace. XML è rigido e adatto a documenti e configurazioni (web.xml, pom.xml), HTML è tollerante e ha un vocabolario fisso; JSON è l'alternativa più compatta per scambiare dati e non ha attributi, schema standard o contenuto misto.Linguaggi di markup - SGML, HTML e XML →, HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →, CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout → e JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →.

Il protocollo di trasporto, cioè HTTP, è già trattato in HTTP 0.9 e 1.0 - struttura dei messaggi, header e parsingHTTP/0.9 (1991) ha una sola riga di richiesta "GET /percorso" e la risposta e' solo il documento HTML, senza codici di stato ne' header, e la connessione si chiude alla fine; HTTP/1.0 (RFC 1945) aggiunge Request-Line con versione, Status-Line con codice, header (generali, di richiesta, di risposta, di entita'), i metodi HEAD e POST, tipi di contenuto diversi dall'HTML; un messaggio e' riga iniziale, header "Nome: valore" a righe CRLF, riga vuota, corpo; in HTTP/1.0 il corpo della risposta finisce quando il server chiude la connessione, mentre per POST serve Content-Length; il parsing legge la prima riga, poi gli header fino alla riga vuota, poi il corpo; i nomi degli header non distinguono maiuscole e minuscole, e un client robusto accetta LF semplice e spazi variabili.HTTP 0.9 e 1.0 - struttura dei messaggi, header e parsing →, HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encodingHTTP/1.1 (oggi RFC 9110 e 9112) rende la connessione persistente di default (si chiude solo con "Connection: close"), rende obbligatorio l'header Host (virtual hosting) e introduce i nuovi metodi PUT, DELETE, OPTIONS, TRACE, Expect: 100-continue, richieste di intervalli (206) e Transfer-Encoding: chunked; con la connessione persistente il client deve sapere dove finisce ogni risposta: lunghezza del corpo nell'ordine HEAD/1xx/204/304 senza corpo, Transfer-Encoding chunked, Content-Length, altrimenti fino alla chiusura; il chunked divide il corpo in blocchi preceduti dalla lunghezza in esadecimale, termina con un chunk 0 e un trailer facoltativo, e si decodifica contando i byte dichiarati (non cercando CRLF).HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encoding → e Caching, autenticazione, tipi MIME e URI in HTTPLa cache HTTP riusa le risposte senza contattare il server finche' sono fresche (Cache-Control: max-age, Expires; in mancanza una durata euristica pari a circa il 10% del tempo trascorso da Last-Modified) e, quando sono scadute, le rivalida con una richiesta condizionale (If-None-Match con ETag, If-Modified-Since con Last-Modified) alla quale il server risponde 304 senza corpo; no-store vieta di memorizzare, no-cache obbliga a rivalidare, private esclude le cache condivise. L'autenticazione usa 401 con WWW-Authenticate e la risposta Authorization: Basic (base64 di utente:password, solo sopra TLS) o Digest (hash con nonce); 407 vale per i proxy. Content-Type porta il tipo MIME (tipo/sottotipo; parametri come charset e boundary), Accept e gli altri header Accept-* guidano la negoziazione. Un URI (RFC 3986) e' scheme://userinfo@host:porta/percorso?query#frammento, con percent-encoding %HH per i byte non ammessi e regole per risolvere i riferimenti relativi.Caching, autenticazione, tipi MIME e URI in HTTP →. Qui lo si richiama soltanto.

L'esempio che useremo

In tutta la parte di tecnologie web si sviluppa una piccola applicazione di prenotazione delle aule. Il database ha due tabelle (schema e vincoli come in SQL - definizione dei dati e vincoliSQL (standard ISO 9075) è un linguaggio dichiarativo con una parte di definizione dei dati (DDL: CREATE/DROP/ALTER di database, schemi, tipi enumerati, domini, tabelle) e una di manipolazione (DML: INSERT, DELETE, UPDATE, SELECT). Una tabella SQL è un multi-insieme di righe (può avere duplicati), quindi non è una relazione in senso stretto. CREATE TABLE elenca colonne con tipo e vincoli: NOT NULL, DEFAULT, CHECK (di colonna o di tupla), PRIMARY KEY (una sola, anche composta), UNIQUE, FOREIGN KEY ... REFERENCES con ON DELETE/ON UPDATE (NO ACTION, CASCADE, SET NULL, SET DEFAULT). I tipi principali sono CHAR/VARCHAR, NUMERIC, INTEGER, SERIAL, BOOLEAN, DATE, TIME, TIMESTAMP, più UUID, intervalli e JSON in PostgreSQL. DROP ... CASCADE cancella anche gli oggetti dipendenti, RESTRICT (predefinito) rifiuta se ce ne sono. DELETE e UPDATE senza WHERE agiscono su tutta la tabella.SQL - definizione dei dati e vincoli → e Modello relazionale - relazioni, chiavi e vincoliIl modello relazionale (Codd, IBM, 1970) rappresenta i dati con relazioni, cioè tabelle, ed è basato su valori: i legami tra relazioni sono confronti di valori, non puntatori, il che garantisce indipendenza dalle strutture fisiche, portabilità e bidirezionalità. Una relazione matematica è un sottoinsieme del prodotto cartesiano di n domini (insieme di n-uple ordinate, senza duplicati né ordine tra le righe); una relazione del modello è un insieme di tuple, funzioni dagli attributi ai valori del dominio, quindi non posizionale. Si distinguono schema di relazione e istanza, schema di base di dati (relazioni più vincoli) e istanza. NULL è un valore speciale fuori da ogni dominio. I vincoli di integrità sono intra-relazionali (di dominio, di tupla, di chiave) e inter-relazionali (integrità referenziale, con la chiave esterna). Superchiave: insieme di attributi che non ripete mai i valori; chiave: superchiave minimale; ogni relazione ne ha almeno una (tutti gli attributi); la chiave primaria è una chiave scelta, senza NULL.Modello relazionale - relazioni, chiavi e vincoli →):

sql
CREATE TABLE aula (
  id    INTEGER PRIMARY KEY,
  nome  VARCHAR(40) NOT NULL UNIQUE,
  posti INTEGER NOT NULL CHECK (posti > 0)
);

CREATE TABLE prenotazione (
  id         INTEGER PRIMARY KEY,
  aula_id    INTEGER NOT NULL REFERENCES aula(id),
  giorno     DATE NOT NULL,
  ora_inizio TIME NOT NULL,
  ora_fine   TIME NOT NULL,
  studente   VARCHAR(40) NOT NULL,
  CHECK (ora_fine > ora_inizio)
);

I dati di esempio, che si ritrovano in tutte le note e gli esercizi:

aula.id nome posti
1 Aula A1 80
2 Aula B2 45
3 Lab Info 30
prenotazione.id aula_id giorno ora_inizio ora_fine studente
1 1 2026-10-19 09:00 11:00 Rossi
2 1 2026-10-19 14:00 16:00 Bianchi
3 2 2026-10-20 10:00 12:00 Verdi
4 3 2026-10-21 09:00 13:00 Rossi

Il server espone i dati come JSON all'indirizzo /api/aule e /api/prenotazioni (con la lista delle prenotazioni di un giorno: /api/prenotazioni?giorno=2026-10-19); una pagina HTML con JavaScript li mostra e permette di prenotare. In JSON i nomi dei campi sono quelli delle colonne (aula_id, ora_inizio, ora_fine).

Client e server

Il modello di base è client-server: due programmi comunicano in rete, il client (client) apre la conversazione e chiede qualcosa, il server (server) resta in ascolto e risponde. Sul web:

  • il client è il browser (web browser): Firefox, Chrome, Safari, Edge;
  • il server è un programma in ascolto di solito sulla porta 80 (HTTP) o 443 (HTTPS);
  • si parlano in HTTP: il client manda una richiesta (metodo, indirizzo, intestazioni, eventuale corpo), il server manda una risposta (codice di stato, intestazioni, corpo).

Esempio. Il browser chiede le prenotazioni del 19 ottobre e il server risponde con un array JSON (207 byte di corpo):

GET /api/prenotazioni?giorno=2026-10-19 HTTP/1.1
Host: aule.example.org
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 207

[{"id":1,"aula_id":1,"giorno":"2026-10-19","ora_inizio":"09:00","ora_fine":"11:00","studente":"Rossi"},{"id":2,"aula_id":1,"giorno":"2026-10-19","ora_inizio":"14:00","ora_fine":"16:00","studente":"Bianchi"}]

La riga vuota separa le intestazioni dal corpo; Content-Length conta i byte del corpo (HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encodingHTTP/1.1 (oggi RFC 9110 e 9112) rende la connessione persistente di default (si chiude solo con "Connection: close"), rende obbligatorio l'header Host (virtual hosting) e introduce i nuovi metodi PUT, DELETE, OPTIONS, TRACE, Expect: 100-continue, richieste di intervalli (206) e Transfer-Encoding: chunked; con la connessione persistente il client deve sapere dove finisce ogni risposta: lunghezza del corpo nell'ordine HEAD/1xx/204/304 senza corpo, Transfer-Encoding chunked, Content-Length, altrimenti fino alla chiusura; il chunked divide il corpo in blocchi preceduti dalla lunghezza in esadecimale, termina con un chunk 0 e un trailer facoltativo, e si decodifica contando i byte dichiarati (non cercando CRLF).HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encoding →). Le due metà sono in realtà messaggi separati: richiesta del client, poi risposta del server.

Due conseguenze importanti di HTTP (RFC 9110):

  1. È senza stato (stateless): ogni richiesta è indipendente, il server non si ricorda delle precedenti. Per sapere "chi è l'utente" il server assegna un identificativo di sessione (session) che il browser rimanda a ogni richiesta in un cookie (RFC 6265). Lo stato (utente, carrello) sta sul server e il cookie ne è la chiave.
  2. È il client a prendere l'iniziativa. Il server non può "spingere" dati al browser di sua iniziativa con HTTP semplice; per notifiche in tempo reale esistono altri meccanismi (WebSocket, QUIC e HTTP-3HTTP e' richiesta e risposta, quindi poco adatto a notifiche e dati in tempo reale (polling, long polling, SSE); WebSocket (RFC 6455) apre con un handshake HTTP/1.1 Upgrade (Sec-WebSocket-Key a 16 byte casuali in Base64, risposta 101 con Sec-WebSocket-Accept = Base64 di SHA-1 di chiave piu' GUID fisso) un canale bidirezionale persistente sulla stessa connessione TCP, con frame di 2-14 byte di intestazione (FIN, opcode, MASK, lunghezza su 7, 16 o 64 bit, chiave di mascheramento obbligatoria dal client al server) e messaggi di testo, binari, close, ping e pong. QUIC (RFC 9000) e' un protocollo di trasporto sopra UDP con TLS 1.3 integrato, flussi indipendenti (niente head-of-line blocking fra flussi), connection ID che permettono di cambiare rete, handshake in 1 RTT e ripresa in 0 RTT; HTTP/3 (RFC 9114) mappa HTTP su QUIC con un flusso per richiesta e QPACK per gli header, ed e' annunciato con Alt-Svc.WebSocket, QUIC e HTTP-3 →).

Architettura a livelli

Un'applicazione a dati si divide quasi sempre in tre livelli (tier), ciascuno con un compito (Organizzazione fisica dei dati e accesso programmatico alle basi di datiUn DBMS è formato da un gestore delle connessioni, un parser, un ottimizzatore che sceglie il piano di esecuzione usando le statistiche del catalogo, un esecutore, i metodi di accesso (heap, ordinato, hash, B-tree, indici), il buffer manager e il gestore delle transazioni (lock e log). Il costo si misura in accessi a blocchi del disco. L'ottimizzatore riscrive l'espressione algebrica (selezioni e proiezioni il prima possibile, prodotto con selezione = join, ordine dei join) e sceglie gli algoritmi: scansione o indice per le selezioni, nested loop, block nested loop, index nested loop, sort-merge o hash join per i join (con 1000 e 100 blocchi, 10 pagine di buffer: 11 mila accessi con block nested loop, 3300 con hash join). La progettazione fisica sceglie organizzazione dei file, indici ed eventuale denormalizzazione in base al carico. Le applicazioni accedono ai dati con SQL incorporato, interfacce a livello di chiamata (ODBC, JDBC, DB-API di Python), ORM o routine memorizzate: connessione, cursore, execute con parametri, fetch, commit o rollback. Mai concatenare l'input dell'utente nell'SQL (SQL injection): query parametrizzate. Un'applicazione web è a tre livelli: browser, server applicativo (HTTP senza stato, sessioni e cookie) e DBMS.Organizzazione fisica dei dati e accesso programmatico alle basi di dati →, sezione sulle applicazioni web):

livello compito nell'esempio
presentazione (presentation) mostrare i dati, raccogliere input, reagire ai clic pagina HTML, CSS e JavaScript nel browser
logica applicativa (business logic) regole: "un'aula non si prenota due volte nella stessa ora", autenticazione, formato delle risposte servlet Java (AuleServlet, PrenotazioniServlet) sul server
dati (data) memorizzare e interrogare in modo persistente database con le tabelle aula e prenotazione, accessibili con AulaDAO e PrenotazioneDAO

Ogni livello parla solo con quelli adiacenti: il browser non apre mai una connessione al database; il database non sa nulla di HTML. I vantaggi:

  • si può cambiare un livello senza toccare gli altri (nuovo database, nuova grafica, un'app per telefono che riusa la stessa logica);
  • si scala per livello: più copie del server applicativo davanti allo stesso database;
  • la sicurezza si concentra nella logica: il browser è fuori dal controllo dell'applicazione (l'utente può modificare qualsiasi cosa), quindi ogni controllo fatto in JavaScript va rifatto sul server. La validazione dei form nel browser serve solo per essere comodi.

Livello (tier) e strato (layer). Il livello è una divisione fisica: macchine o processi distinti. Lo strato è una divisione logica del codice (per esempio, dentro l'applicazione Java: servlet, classi di dominio, classi di accesso ai dati). Un'applicazione a tre livelli ha tipicamente più strati nel livello centrale, e la divisione in strati secondo il paradigma MVC (Model-View-Controller) è un tema della parte lato server.

Confronto con le alternative:

  • a due livelli (two-tier): il client parla direttamente con il database (le vecchie applicazioni desktop che usavano JDBC). La logica sta nel client, che va installato e aggiornato su ogni PC, e le credenziali del database sono esposte;
  • a tre o più livelli (n-tier): si aggiungono per esempio una cache, un servizio di autenticazione, altri servizi interni.

Un client sottile (thin client) lascia al server quasi tutta la logica e riceve pagine già pronte (il web classico); un client spesso (thick o rich client) esegue molta logica in JavaScript e scambia solo dati (applicazioni a pagina singola, single-page application).

Server web e application server

Sul lato server ci sono due ruoli che nei sistemi reali si incontrano nello stesso prodotto o in prodotti diversi:

Tomcat può fare anche da server web (serve i file statici di una applicazione), ma in produzione spesso c'è un reverse proxy davanti: nginx o Apache ricevono le richieste dal browser, rispondono direttamente per i file statici e inoltrano all'application server solo quelle dinamiche (/api/...) (DNS, proxy web, HTTP CONNECT e gateway applicativiUn programma risolve i nomi con getaddrinfo (file hosts e poi DNS); un messaggio DNS (RFC 1035) ha un header di 12 byte (ID, flag QR/RD/RA/TC e RCODE, quattro contatori), una domanda (QNAME a etichette con lunghezza, QTYPE, QCLASS) e record di risposta con nomi eventualmente compressi da puntatori, su UDP porta 53 con ripiego su TCP se il bit TC e' acceso; un web proxy e' un intermediario scelto dal client che riceve richieste con URI assoluto, le inoltra al server (togliendo gli header hop-by-hop, aggiungendo Via e X-Forwarded-For) e puo' memorizzare le risposte; le cache si organizzano in gerarchie e con funzioni hash coerenti, le CDN le replicano vicino agli utenti; il metodo CONNECT chiede al proxy un tunnel TCP verso host:porta e dopo la risposta 2xx il proxy inoltra i byte in entrambe le direzioni senza interpretarli (HTTPS, con restrizione delle porte); un gateway o reverse proxy e' un intermediario scelto dal server che traduce o inoltra le richieste ad altri sistemi (bilanciamento, terminazione TLS, FastCGI, API gateway).DNS, proxy web, HTTP CONNECT e gateway applicativi →). Si ottengono HTTPS in un solo punto, compressione, bilanciamento del carico fra più istanze.

Pagine statiche e dinamiche.

statica dinamica
contenuto file che esiste così com'è sul server prodotto al momento della richiesta
esempio /stile.css, /index.html elenco delle prenotazioni di oggi
chi la produce il web server un programma: CGI, servlet, JSP, PHP...
varia con niente (stesso file per tutti) parametri della richiesta, utente, ora, contenuto del database

Anche una pagina "statica" può diventare dinamica nel browser: l'HTML è sempre lo stesso, ma JavaScript lo modifica dopo il caricamento (per esempio costruisce la tabella delle prenotazioni da un array JSON). Quindi "dinamico" può accadere sul server, sul client o in entrambi: è la differenza fra Web 1.0 e Web 2.0 più sotto.

Che cosa fa un browser

Un browser contiene sei componenti principali: l'interfaccia (barra degli indirizzi, schede), il motore di rete (HTTP, cache, cookie), il motore di rendering (rendering engine: parsing e disegno), l'interprete JavaScript, il gestore di memorizzazione (cookie, localStorage) e il motore grafico. Quando si digita un indirizzo:

  1. Rete. Risoluzione DNS, connessione TCP e TLS, richiesta GET, risposta con Content-Type: text/html (DNS, proxy web, HTTP CONNECT e gateway applicativiUn programma risolve i nomi con getaddrinfo (file hosts e poi DNS); un messaggio DNS (RFC 1035) ha un header di 12 byte (ID, flag QR/RD/RA/TC e RCODE, quattro contatori), una domanda (QNAME a etichette con lunghezza, QTYPE, QCLASS) e record di risposta con nomi eventualmente compressi da puntatori, su UDP porta 53 con ripiego su TCP se il bit TC e' acceso; un web proxy e' un intermediario scelto dal client che riceve richieste con URI assoluto, le inoltra al server (togliendo gli header hop-by-hop, aggiungendo Via e X-Forwarded-For) e puo' memorizzare le risposte; le cache si organizzano in gerarchie e con funzioni hash coerenti, le CDN le replicano vicino agli utenti; il metodo CONNECT chiede al proxy un tunnel TCP verso host:porta e dopo la risposta 2xx il proxy inoltra i byte in entrambe le direzioni senza interpretarli (HTTPS, con restrizione delle porte); un gateway o reverse proxy e' un intermediario scelto dal server che traduce o inoltra le richieste ad altri sistemi (bilanciamento, terminazione TLS, FastCGI, API gateway).DNS, proxy web, HTTP CONNECT e gateway applicativi →).
  2. Decodifica e tokenizzazione. I byte diventano caratteri (con la codifica dichiarata, UTF-8), poi il tokenizzatore HTML li trasforma in token: tag di apertura, tag di chiusura, testo, commenti.
  3. Costruzione del DOM. Dai token si costruisce il DOM (Document Object Model), un albero in memoria dove ogni tag diventa un nodo elemento e il testo un nodo testo. L'algoritmo è definito da WHATWG HTML e non fallisce mai: davanti a un HTML sbagliato corregge (chiude i tag mancanti, mette il <tbody> che manca) invece di dare errore. Per questo il DOM può differire dal sorgente.
  4. CSSOM. Ogni foglio di stile (<link rel="stylesheet">, <style>) viene analizzato in un albero di regole, il CSSOM. Per ogni nodo del DOM si calcola lo stile finale applicando la cascata (CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →).
  5. Render tree. Unendo DOM e CSSOM si ottiene l'albero di rendering, che contiene solo i nodi visibili (un <head> o un elemento con display: none non ci sono) con il loro stile.
  6. Layout. Per ogni nodo si calcolano posizione e dimensione in pixel, a partire dalla larghezza della finestra. Se la finestra cambia o un elemento cambia misura, il layout si ricalcola (reflow).
  7. Paint e composizione. Si dipingono i pixel (testo, colori, bordi, immagini) in strati che la scheda grafica compone sullo schermo. Un cambio di solo colore richiede solo il repaint, senza nuovo layout.

Esempio: il documento

html
<!DOCTYPE html>
<html lang="it">
<head><title>Aule</title></head>
<body>
  <h1>Aule</h1>
  <ul><li>Aula A1</li><li>Lab Info</li></ul>
</body>
</html>

dà questo DOM (rientro = figlio):

Document
└─ html (lang="it")
   ├─ head
   │  └─ title
   │     └─ "Aule"
   └─ body
      ├─ h1
      │  └─ "Aule"
      └─ ul
         ├─ li ─ "Aula A1"
         └─ li ─ "Lab Info"

Gli spazi e i ritorni a capo fra i tag diventano a loro volta nodi di testo (qui omessi). Ogni nodo ha un padre e dei figli: è questa struttura che JavaScript naviga e modifica (JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →).

Script, CSS e blocco del rendering

Il parser HTML lavora mentre i byte arrivano, ma due cose lo rallentano:

  • un foglio di stile blocca il rendering (il browser non disegna finché non l'ha caricato, per non mostrare una pagina senza stile) e anche l'esecuzione degli script che seguono, che potrebbero leggere gli stili;
  • uno script classico <script src="app.js"></script> blocca il parsing: il parser si ferma, scarica ed esegue lo script, poi riprende, perché lo script può modificare il documento con document.write.

Gli attributi che cambiano questo comportamento:

attributo scarica esegue
nessuno fermando il parser subito, fermando il parser
defer in parallelo al parsing dopo la fine del parsing, nell'ordine in cui compaiono, prima di DOMContentLoaded
async in parallelo appena scaricato, in ordine qualsiasi
type="module" in parallelo come defer

Regola pratica: gli script che toccano il DOM vanno con defer nell'<head> o in fondo al <body>. L'evento DOMContentLoaded scatta quando il DOM è completo (immagini escluse); load quando è arrivato tutto, immagini comprese.

Origine e same-origin policy

Un'origine (origin) è la terna schema + host + porta: https://aule.example.org e https://aule.example.org:8443 sono origini diverse, come http:// e https://. La same-origin policy impedisce a uno script caricato da un'origine di leggere le risposte di un'altra: una pagina qualsiasi non può leggere i dati che l'utente ha su un altro sito. Un server può autorizzare esplicitamente altre origini con le intestazioni CORS (cross-origin resource sharing). Il caso tipico dell'esempio: pagina e API sono servite dalla stessa origine, e la policy non dà problemi.

Web 1.0, 2.0 e 3.0

Web 1.0 Web 2.0 Web 3.0 (web semantico)
idea pubblicare documenti applicazioni e contenuti degli utenti dati con un significato leggibile dalle macchine
lato client HTML (quasi) senza script JavaScript, AJAX, CSS, applicazioni a pagina singola uguale al Web 2.0
lato server pagine generate dal server (CGI, servlet, JSP): ogni clic ricarica tutta la pagina servizi web (REST) che restituiscono dati (JSON) dati pubblicati in RDF, collegati fra loro (linked data)
esempio il sito statico di un dipartimento un calendario che si aggiorna senza ricaricare un catalogo i cui dati altri siti possono interrogare con SPARQL

Un'interazione completa nell'esempio

L'utente apre https://aule.example.org/ e vede le prenotazioni di oggi.

  1. Il browser fa GET / (e poi /prenotazioni.css, /prenotazioni.js). Il web server risponde con i file statici.
  2. Il browser costruisce DOM e CSSOM e disegna la pagina senza tabella; lo script (con defer) parte a fine parsing.
  3. Lo script fa fetch("/api/prenotazioni?giorno=2026-10-19"). Il web server inoltra la richiesta all'application server.
  4. La servlet PrenotazioniServlet legge il parametro, chiama PrenotazioneDAO, che esegue la query parametrizzata SELECT ... WHERE giorno = ? sul DBMS.
  5. La servlet trasforma le righe in JSON e risponde 200 OK.
  6. Lo script riceve l'array, costruisce le righe della tabella con il DOM e il browser fa layout e paint solo per la parte nuova.

Tre richieste HTTP, tre livelli, nessun ricaricamento della pagina.

Errori tipici

  • Credere che il browser "esegua" il server: HTML e CSS sono dati, JavaScript viene eseguito nel browser, il Java delle servlet nel container.
  • Mettere la validazione solo in JavaScript: il controllo è aggirabile, va rifatto sul server.
  • Dimenticare che HTTP è senza stato: senza cookie di sessione il server non riconosce l'utente.
  • Confondere web server e application server: il primo serve file e inoltra, il secondo esegue codice.
  • Mettere uno <script> bloccante in cima al <head> e stupirsi che la pagina compaia in ritardo (usare defer).
  • Pensare che il DOM sia identico al sorgente: il parser corregge gli errori.
  • Aprire una pagina con fetch da file:// e vedere fallire le richieste: l'origine è diversa, servono pagine servite da un server.

Domande d'esame

  1. Descrivere l'architettura a tre livelli di un'applicazione web e dire dove va fatta la validazione dei dati. Presentazione (browser), logica applicativa (application server), dati (DBMS); ogni livello parla con l'adiacente. La validazione nel browser è comodità, quella obbligatoria è sul server, perché il client non è fidato.
  2. Che cosa succede dal momento in cui il browser riceve l'HTML a quando la pagina è visibile? Decodifica e tokenizzazione, DOM, CSSOM, render tree, layout, paint e composizione; gli script senza defer/async bloccano il parsing, i fogli di stile bloccano il rendering.
  3. Differenza fra web server e application server, e fra Web 1.0 e Web 2.0. Il web server serve file e inoltra; l'application server (per esempio Tomcat) esegue le servlet. Nel Web 1.0 il server genera pagine intere a ogni azione, nel Web 2.0 il browser carica una volta la pagina e scambia dati (AJAX, JSON, REST) con il server.

Versione ripasso

Esempio conduttore. Prenotazione aule: tabelle aula(id, nome, posti) e prenotazione(id, aula_id, giorno, ora_inizio, ora_fine, studente); JSON a /api/aule e /api/prenotazioni?giorno=....

Client-server e HTTP. Il client (browser) apre la conversazione, il server risponde (HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encodingHTTP/1.1 (oggi RFC 9110 e 9112) rende la connessione persistente di default (si chiude solo con "Connection: close"), rende obbligatorio l'header Host (virtual hosting) e introduce i nuovi metodi PUT, DELETE, OPTIONS, TRACE, Expect: 100-continue, richieste di intervalli (206) e Transfer-Encoding: chunked; con la connessione persistente il client deve sapere dove finisce ogni risposta: lunghezza del corpo nell'ordine HEAD/1xx/204/304 senza corpo, Transfer-Encoding chunked, Content-Length, altrimenti fino alla chiusura; il chunked divide il corpo in blocchi preceduti dalla lunghezza in esadecimale, termina con un chunk 0 e un trailer facoltativo, e si decodifica contando i byte dichiarati (non cercando CRLF).HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encoding →, Caching, autenticazione, tipi MIME e URI in HTTPLa cache HTTP riusa le risposte senza contattare il server finche' sono fresche (Cache-Control: max-age, Expires; in mancanza una durata euristica pari a circa il 10% del tempo trascorso da Last-Modified) e, quando sono scadute, le rivalida con una richiesta condizionale (If-None-Match con ETag, If-Modified-Since con Last-Modified) alla quale il server risponde 304 senza corpo; no-store vieta di memorizzare, no-cache obbliga a rivalidare, private esclude le cache condivise. L'autenticazione usa 401 con WWW-Authenticate e la risposta Authorization: Basic (base64 di utente:password, solo sopra TLS) o Digest (hash con nonce); 407 vale per i proxy. Content-Type porta il tipo MIME (tipo/sottotipo; parametri come charset e boundary), Accept e gli altri header Accept-* guidano la negoziazione. Un URI (RFC 3986) e' scheme://userinfo@host:porta/percorso?query#frammento, con percent-encoding %HH per i byte non ammessi e regole per risolvere i riferimenti relativi.Caching, autenticazione, tipi MIME e URI in HTTP →). HTTP è senza stato: l'utente si riconosce con un cookie di sessione. Il server non spedisce dati di sua iniziativa (WebSocket, QUIC e HTTP-3HTTP e' richiesta e risposta, quindi poco adatto a notifiche e dati in tempo reale (polling, long polling, SSE); WebSocket (RFC 6455) apre con un handshake HTTP/1.1 Upgrade (Sec-WebSocket-Key a 16 byte casuali in Base64, risposta 101 con Sec-WebSocket-Accept = Base64 di SHA-1 di chiave piu' GUID fisso) un canale bidirezionale persistente sulla stessa connessione TCP, con frame di 2-14 byte di intestazione (FIN, opcode, MASK, lunghezza su 7, 16 o 64 bit, chiave di mascheramento obbligatoria dal client al server) e messaggi di testo, binari, close, ping e pong. QUIC (RFC 9000) e' un protocollo di trasporto sopra UDP con TLS 1.3 integrato, flussi indipendenti (niente head-of-line blocking fra flussi), connection ID che permettono di cambiare rete, handshake in 1 RTT e ripresa in 0 RTT; HTTP/3 (RFC 9114) mappa HTTP su QUIC con un flusso per richiesta e QPACK per gli header, ed e' annunciato con Alt-Svc.WebSocket, QUIC e HTTP-3 →).

Tre livelli (Organizzazione fisica dei dati e accesso programmatico alle basi di datiUn DBMS è formato da un gestore delle connessioni, un parser, un ottimizzatore che sceglie il piano di esecuzione usando le statistiche del catalogo, un esecutore, i metodi di accesso (heap, ordinato, hash, B-tree, indici), il buffer manager e il gestore delle transazioni (lock e log). Il costo si misura in accessi a blocchi del disco. L'ottimizzatore riscrive l'espressione algebrica (selezioni e proiezioni il prima possibile, prodotto con selezione = join, ordine dei join) e sceglie gli algoritmi: scansione o indice per le selezioni, nested loop, block nested loop, index nested loop, sort-merge o hash join per i join (con 1000 e 100 blocchi, 10 pagine di buffer: 11 mila accessi con block nested loop, 3300 con hash join). La progettazione fisica sceglie organizzazione dei file, indici ed eventuale denormalizzazione in base al carico. Le applicazioni accedono ai dati con SQL incorporato, interfacce a livello di chiamata (ODBC, JDBC, DB-API di Python), ORM o routine memorizzate: connessione, cursore, execute con parametri, fetch, commit o rollback. Mai concatenare l'input dell'utente nell'SQL (SQL injection): query parametrizzate. Un'applicazione web è a tre livelli: browser, server applicativo (HTTP senza stato, sessioni e cookie) e DBMS.Organizzazione fisica dei dati e accesso programmatico alle basi di dati →):

  • presentazione: HTML, CSS, JavaScript nel browser;
  • logica: servlet sull'application server;
  • dati: DBMS (AulaDAO, PrenotazioneDAO). Ogni livello parla solo con l'adiacente. Vantaggi: sostituibilità, scalabilità, sicurezza centralizzata. Livello = divisione fisica, strato = divisione logica del codice. Client sottile = pagine pronte dal server; client spesso = logica in JavaScript.

Web server e application server. Web server (httpd, nginx): file statici, HTTPS, cache, reverse proxy. Application server / container (Tomcat): esegue codice (servlet), sessioni, ciclo di vita (CGI e applicazioni web dinamicheLa Common Gateway Interface (CGI, RFC 3875) e' l'interfaccia fra un server web e un programma esterno che genera la risposta: per ogni richiesta il server fa fork ed exec del programma, gli passa i dati con le meta-variabili d'ambiente (REQUEST_METHOD, QUERY_STRING, CONTENT_LENGTH, CONTENT_TYPE, SCRIPT_NAME, PATH_INFO, SERVER_*, REMOTE_ADDR, HTTP_* per gli header) e con lo standard input (corpo della POST, CONTENT_LENGTH byte); il programma scrive sullo standard output header CGI (Content-Type obbligatorio, Status, Location), una riga vuota e il corpo, e il server li trasforma in una risposta HTTP completa; i punti delicati sono pipe e dup2, la chiusura delle estremita' inutilizzate, il timeout, i limiti di dimensione e la sicurezza (injection, path traversal, header Proxy, shellshock); il costo di un processo per richiesta ha portato a FastCGI, ai moduli del server e ai server applicativi.CGI e applicazioni web dinamiche →). Pagina dinamica = prodotta al momento della richiesta (server) o modificata dopo il caricamento (client).

Pipeline del browser.

  1. rete (DNS, TCP/TLS, GET);
  2. decodifica e tokenizzazione;
  3. DOM (il parser corregge gli errori, non fallisce);
  4. CSSOM e stile calcolato;
  5. render tree (solo nodi visibili);
  6. layout (reflow);
  7. paint e composizione.

Blocchi. Script classico: blocca il parsing. defer: dopo il parsing, in ordine. async: appena scaricato. type="module": come defer. Il CSS blocca il rendering. DOMContentLoaded = DOM pronto; load = tutto caricato.

Origine = schema + host + porta; la same-origin policy impedisce di leggere risposte di altre origini (si apre con CORS).

Web 1.0 pagine intere generate dal server, ogni clic ricarica. Web 2.0 AJAX/fetch, JSON, servizi REST (Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST →). Web 3.0 dati con significato (RDF, linked data).

Errori tipici

  • Validare solo nel browser.
  • Dimenticare che HTTP è senza stato.
  • Confondere web server e application server.
  • Script bloccante senza defer.
  • Pensare che il DOM coincida col sorgente.

Seguito: Linguaggi di markup - SGML, HTML e XMLUn linguaggio di markup aggiunge al testo marcatori che ne descrivono la struttura. SGML (ISO 8879, 1986) è il metalinguaggio da cui derivano HTML fino alla 4.01 e XML 1.0 (W3C, 1998, un sottoinsieme semplificato); HTML5 ha un proprio algoritmo di parsing, tollerante, e non è né SGML né XML. Un documento XML è ben formato se rispetta la sintassi (un'unica radice, tag annidati e chiusi, attributi tra virgolette, nomi con maiuscole e minuscole distinte, entità per i caratteri speciali) ed è valido se in più rispetta uno schema. La DTD dichiara elementi (ELEMENT: EMPTY, ANY, #PCDATA, sequenza con la virgola, scelta con |, cardinalità ? * +) e attributi (ATTLIST: CDATA, ID, IDREF, enumerazioni; #REQUIRED, #IMPLIED, #FIXED); non ha tipi di dato e non conosce i namespace. XML Schema (XSD) è scritto in XML e ha tipi (xs:date, xs:positiveInteger), restrizioni con pattern, minOccurs e maxOccurs, key e keyref. I namespace (xmlns, xmlns:prefisso) identificano il vocabolario con un URI; gli attributi senza prefisso non appartengono a nessun namespace. XML è rigido e adatto a documenti e configurazioni (web.xml, pom.xml), HTML è tollerante e ha un vocabolario fisso; JSON è l'alternativa più compatta per scambiare dati e non ha attributi, schema standard o contenuto misto.Linguaggi di markup - SGML, HTML e XML →, HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →, CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →, JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →. Schema dei livelli.

livello compito nell'esempio
presentazione mostrare, raccogliere input HTML, CSS, JavaScript nel browser
logica regole, autenticazione, formato delle risposte AuleServlet, PrenotazioniServlet
dati memorizzare e interrogare tabelle aula, prenotazione; AulaDAO, PrenotazioneDAO

Il browser non apre mai connessioni al database; ogni controllo fatto in JavaScript va rifatto sul server. Due livelli = client che parla col DB (credenziali esposte, client da aggiornare ovunque); tre o più = aggiunte di cache, autenticazione, altri servizi.

Scambio HTTP dell'esempio.

GET /api/prenotazioni?giorno=2026-10-19 HTTP/1.1
Host: aule.example.org
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 207

Corpo: array JSON con le prenotazioni 1 e 2. HTTP è senza stato: la sessione dell'utente sta sul server, il cookie ne è la chiave (Caching, autenticazione, tipi MIME e URI in HTTPLa cache HTTP riusa le risposte senza contattare il server finche' sono fresche (Cache-Control: max-age, Expires; in mancanza una durata euristica pari a circa il 10% del tempo trascorso da Last-Modified) e, quando sono scadute, le rivalida con una richiesta condizionale (If-None-Match con ETag, If-Modified-Since con Last-Modified) alla quale il server risponde 304 senza corpo; no-store vieta di memorizzare, no-cache obbliga a rivalidare, private esclude le cache condivise. L'autenticazione usa 401 con WWW-Authenticate e la risposta Authorization: Basic (base64 di utente:password, solo sopra TLS) o Digest (hash con nonce); 407 vale per i proxy. Content-Type porta il tipo MIME (tipo/sottotipo; parametri come charset e boundary), Accept e gli altri header Accept-* guidano la negoziazione. Un URI (RFC 3986) e' scheme://userinfo@host:porta/percorso?query#frammento, con percent-encoding %HH per i byte non ammessi e regole per risolvere i riferimenti relativi.Caching, autenticazione, tipi MIME e URI in HTTP →).

Web server e application server.

web server application server / container
esempi Apache httpd, nginx Tomcat (servlet)
compito file statici, HTTPS, cache, reverse proxy esegue il codice, sessioni, ciclo di vita

Statica = file così com'è; dinamica = prodotta alla richiesta (CGI, servlet, JSP) oppure modificata dal browser dopo il caricamento.

Interazione completa.

  1. GET / e file statici dal web server.
  2. DOM e CSSOM, prima pagina disegnata; lo script defer parte a fine parsing.
  3. fetch("/api/prenotazioni?giorno=...") inoltrata all'application server.
  4. PrenotazioniServlet e PrenotazioneDAO eseguono la query parametrizzata sul DBMS.
  5. Risposta 200 con JSON.
  6. Lo script costruisce le righe con il DOM; il browser rifà layout e paint solo della parte nuova.

Domande d'esame, tracce.

  • Tre livelli e dove si valida: la validazione obbligatoria è sul server, quella nel browser è comodità.
  • Dall'HTML alla pagina: DOM, CSSOM, render tree, layout, paint; defer e async.
  • Web server contro application server; Web 1.0 contro 2.0: pagine intere contro dati scambiati con AJAX.

Esercizi su questo argomento

Teoria collegata