25. HttpServer e generazione UI HTML
Questo capitolo copre il web server route-first di MALDA, gli handler di pagine HTML, gli helper per pagine generate dall'AI e le utility di cache HTML. Usalo quando vuoi servire pagine con HttpServer e route tradizionali richiesta/risposta.
HttpServer, @PAGE, @AIPAGE e gli helper di generazione HTML. Per i componenti server e ui.*, vedi Componenti server Web UI. Per le route API-first, vedi Server REST API.
25.1 Mappa del capitolo
- 25.2 Ciclo di vita di
HttpServere modello delle route - 25.3 Oggetti request e response
- 25.4 Pagine dinamiche con
@PAGE - 25.5 Pagine generate dall'AI con
@AIPAGE - 25.6
@GET/@POSTnei flussi di hosting delle pagine - 25.7 Redirect e flussi di pagina a più passi
- 25.8 Helper di generazione HTML e caching
- 25.9 Ciclo di vita dalla richiesta al render e note di produzione
- 25.10 Hardening in produzione
- 25.11 Test e risoluzione dei problemi
25.2 Classe HttpServer
La classe HttpServer offre un HTTP server built-in per asset statici, HTML generato sul server, pagine generate dall'AI, gestione dei form e handler di route. Funziona bene per applicazioni route-first in cui ogni richiesta restituisce un documento completo o una risposta mirata.
25.2.1 Costruttore
var server = new HttpServer(port);
// OR
var server = new HttpServer(port, webDirectory); // Custom web directory
// OR
var server = new HttpServer(port, webDirectory, pathBase, host);
port deve essere un intero in 1-65535. Le porte privilegiate (1-1023, es. 80/443) sono ammesse; il bind può comunque richiedere permessi elevati o reservation URL del sistema operativo.
L'host di bind di default è localhost (solo loopback). Passa host come quarto argomento opzionale, chiama setHost(host) prima di start(), oppure imposta la variabile d'ambiente MALDA_HTTP_HOST. Usa 0.0.0.0 o * per ascoltare su tutte le interfacce (stesse regole di prefisso di RestServer). L'host di bind corrente è disponibile come proprietà host.
HTTPS è opzionale e cross-platform. Chiama enableHttps(certPath, password?) prima di start() con un file .pfx/.p12, oppure un PEM .pem/.crt (chiave privata accanto come .key). Alternative da ambiente: MALDA_HTTP_HTTPS=1, MALDA_HTTP_CERT e, opzionale, MALDA_HTTP_CERT_PASSWORD. Proprietà: https, certPath. Il TLS è terminato da Kestrel; la pipeline di richiesta esistente continua a girare su un HttpListener in loopback.
25.2.2 Metodi core
start(): Avvia il server e scansiona le route decorate.stop(): Ferma il server in modo graceful.setHost(host): Imposta l'host di bind prima distart()(localhost, IP/hostname, oppure0.0.0.0/*per tutte le interfacce).enableHttps(certPath, password?)/disableHttps(): Abilita o disabilita TLS prima distart().getRoutes(): Restituisce la tabella delle route registrate.clearCache(): Svuota la cache dei file statici.setHTML(html): Imposta il contenuto HTML per il path root.use(middleware): Registra middleware globale conreq,resenext.enableCsrf(secret, cookieName?, headerName?)/disableCsrf(): Attiva o disattiva la protezione CSRF built-in.enableSession(secret, options?)/disableSession(): Cookie session-id firmato con store in-memory o SQLite; esponereq.sessione gli helper flash.mount(restServer): Serve unRestServersullo stesso listener/porta (prima le route API, poi pagine/componenti/statici).setRateLimit(limit, windowSeconds, keyStrategy?)/disableRateLimit(): Attiva o disattiva il rate limiting degli endpoint.
25.2.3 Esempio host minimo
var server = new HttpServer(8080);
server.start();
print("Server running at http://localhost:8080");
while (server.isRunning) {
sleep(1000);
}
// HTTPS (optional):
// var tls = new HttpServer(8443);
// tls.setHost("0.0.0.0");
// tls.enableHttps("ask.pfx", "secret");
// tls.start();
// print("Server running at https://localhost:8443");
25.3 Oggetti request e response
Gli handler di pagine e route possono ricevere il contesto della richiesta e restituire HTML grezzo oppure un oggetto response strutturato.
- Request:
method,path,query,params,headers,cookies,body,auth,session,correlationId,ip/remoteIp. - Session:
req.session.get/set/delete/clear,flash/getFlash/getFlashes(avvisi di una sola richiesta dopo un redirect). - Helper di response:
status,json,text,html,redirect,header,cookieesend. - Helper di form:
csrfField(secret),bindForm(body, fields),formErrors(errors),pageLayout(title, bodyHtml, options?). Preferisciui.layoutper i template ricchi. - Metadati di route:
@RouteGroup/@Group/@Prefix,@Version/@ApiVersion,@Use/@Middlewaree@Validate.
Quando una route è in stile API, i fallimenti del framework restituiscono un payload JSON standardizzato con status, error, message e correlationId, con details opzionale per i fallimenti di validazione.
25.4 Pagine dinamiche con @PAGE
Usa @PAGE per pagine HTML guidate dalla richiesta. Un handler di pagina può restituire direttamente un documento HTML completo, e i path parameter vengono bound dall'URL.
@PAGE("/")
function handleHome() {
return "<html><body><h1>Home</h1></body></html>";
}
@PAGE("/user/{id}")
function handleUser(id) {
return "<html><body><h1>User: " + id + "</h1></body></html>";
}
Usa @PAGE quando la richiesta deve produrre una pagina completa. Se la pagina ha bisogno di fragment interattivi, aggiornamenti live o stato dei componenti gestito sul server, sposta la UI riutilizzabile in un flusso a componenti e tieni la route come punto di ingresso.
25.5 Pagine generate dall'AI con @AIPAGE
Usa @AIPAGE quando vuoi che MALDA generi l'HTML iniziale a partire da una descrizione in stile prompt.
@AIPAGE("/", "Contact form with name, email, and message fields")
function homePage() {
// AI generates the HTML automatically on first access
return "";
}
- L'AI genera HTML dalla descrizione.
- L'HTML generato viene messo in cache per le prestazioni.
- Lo script helper AJAX viene iniettato automaticamente per l'invio moderno dei form.
- Se non è configurato un modello, l'agente di generazione UI usa l'LLM locale di default (Qwen/Qwen2.5-0.5B-Instruct, scaricato come build GGUF da Hugging Face); puoi anche fornire un
OpenRouterCliente unAgent.
25.5.1 Esempio completo di form AI
var server = new HttpServer(8080);
@AIPAGE("/", "Contact form with name, email, and message fields")
function homePage() {
return "";
}
@POST("/submit")
function handleSubmit(body) {
print("Form submitted!");
print("Name: " + body.name);
print("Email: " + body.email);
print("Message: " + body.message);
return {
"status": 200,
"body": "<html><body><h1>Thank You!</h1><p>Your message has been received.</p><p><a href='/'>Back to form</a></p></body></html>"
};
}
server.start();
25.6 Route GET/POST nei flussi di hosting delle pagine
HttpServer può ospitare route @GET e @POST insieme alle pagine. È utile per handler AJAX, piccoli endpoint JSON o Server-Sent Events usati da una pagina. Per la progettazione API completa, la validazione avanzata e l'organizzazione degli endpoint, usa Server REST API come riferimento principale.
25.6.1 Handler GET
@GET("/api/users")
function getUsers() {
return {"status": 200, "users": ["Alice", "Bob", "Charlie"]};
}
@GET("/api/events")
function getEvents() {
return {"sse": true};
}
- Restituisci oggetti JSON per le risposte normali in stile API.
- Restituisci
{"sse": true}per abilitare SSE. - Usa path parameter come
@GET("/api/users/{id}")quando serve.
25.6.2 Handler POST
@POST("/submit")
function handleSubmit(body) {
print("Name: " + body.name);
print("Email: " + body.email);
return {
"status": 200,
"body": "<html><body><h1>Thank You!</h1></body></html>"
};
}
- Il body della richiesta viene parsato automaticamente come JSON o dati form-urlencoded.
- Il payload parsato è disponibile tramite un parametro
body. - Gli handler POST funzionano bene per gli invii di form da pagine
@PAGEo@AIPAGE.
25.7 Redirect con RedirectTo
Usa redirect(location, status?) per risposte di redirect esplicite, oppure l'alias legacy RedirectTo(location) quando migri codice esistente.
@POST("/login")
function handleLogin(body) {
if (body.username == "admin" && body.password == "secret") {
return redirect("/dashboard");
}
return redirect("/login?error=invalid");
}
@PAGE("/old-page")
function oldPage() {
return redirect("/new-page", 302);
}
Per le app HTML in produzione, preferisci hashing delle password + JWT in un cookie firmato invece di controlli in chiaro. Vedi Examples/Web/auth_cookie_login.malda e gli helper condivisi req.auth (stessa superficie di RestServer).
function requireAuth(req, res, next) {
req.auth.authenticateCookieJwt("session", jwtSecret, cookieSecret);
next();
}
server.use(requireAuth, { "except": ["/", "/login"] });
redirect(location)restituisce un oggetto response con status303 See Othere un headerLocation, che è il default più sicuro dopo un'azione POST.- Passa uno status 3xx esplicito quando ti serve una semantica di redirect diversa, per esempio
redirect("/new-page", 302). RedirectTo(location)resta disponibile come alias di compatibilità e segue lo stesso comportamento di default303.- Funziona sia con le richieste browser normali sia con gli invii di form guidati da AJAX.
25.8 Helper di generazione HTML
MALDA include utility helper per HTML generato e prototipi di UI renderizzata sul server.
25.8.1 Classe HTMLCache
La classe HTMLCache memorizza l'HTML generato per ridurre il lavoro LLM ripetuto e migliorare i tempi di risposta.
var cache = new HTMLCache(cacheDirectory?, maxSize?, expirationHours?);
get(prompt): Ottiene l'HTML in cache oppurenull.set(prompt, html, metadata?): Memorizza l'HTML generato.has(prompt): Controlla se un prompt ha una voce in cache.clear(): Svuota tutte le voci in cache.
25.8.2 Funzione extractHTML
extractHTML(markdown) estrae HTML da code fence markdown oppure restituisce l'HTML così com'è.
var html = extractHTML(markdown);
25.8.3 Funzione markdownToHtml
markdownToHtml(markdown) converte Markdown in un fragment HTML (heading, emphasis, liste, tabelle, codice fenced e simili). I tag HTML grezzi nell'input sono disabilitati, così l'output non attendibile di un modello è più sicuro da incorporare in una pagina. Restituisce una stringa; avvolgila nel chrome del tuo documento.
var body = markdownToHtml("**Hello** and a table:\n\n| A | B |\n|---|---|\n| 1 | 2 |");
return "<html><body class='md'>" + body + "</body></html>";
25.8.4 Funzione generateUI
generateUI è un helper di convenienza per la generazione HTML guidata da prompt, con cache opzionale e un agente personalizzato.
var html = generateUI(description, cache?, agent?);
25.8.5 Funzione ui.generate
Usa ui.generate quando l'AI deve restituire un albero UI server strutturato invece di una stringa HTML.
var tree = ui.generate("Dashboard with title, filter row, and data grid", uiAgent, cache);
var envelope = ui.mountEnvelope(tree, "dashboard-session");
return envelope;
- Il risultato è un oggetto nodo root con
type,props,childrene unkeyopzionale. - Il runtime UI valida l'albero generato prima di restituirlo.
- Usalo quando vuoi l'assistenza AI ma vuoi comunque il protocollo dei componenti server descritto in Componenti server Web UI.
25.9 Ciclo di vita dalla richiesta al render
- Il browser richiede una pagina o una route gestita da
@PAGE,@AIPAGE,@GETo@POST. HttpServerrisolve la route e carica il contesto di richiesta necessario.- L'handler restituisce HTML, un redirect, JSON, SSE o un artefatto UI generato.
- Il browser renderizza il documento restituito, segue il redirect oppure elabora la risposta API.
25.10 Hardening in produzione
- Abilita la protezione CSRF sulle route che mutano con
enableCsrf. - Applica il rate limiting con
setRateLimit(gira dopo il middleware di auth cosìverifiedSubOrIppuò usare il subject JWT come chiave). - Proteggi le route con
req.auth.authenticateBearerJwt/authenticateCookieJwte salta i path pubblici viause(fn, { "except": [...] }). - Valida l'input della richiesta prima della persistenza o degli effetti collaterali.
- Usa i correlation ID nei log per il debug a livello di route.
- Svuota le cache HTML generate quando cambia il contratto del prompt o il template della pagina.
25.11 Test e risoluzione dei problemi
- Usa
getRoutes()per verificare che le route di pagina e handler siano state registrate. - Se una pagina non si aggiorna dopo cambi al prompt, svuota sia la cache del server sia la voce
HTMLCache. - Per i problemi sui form, conferma la forma del body che l'handler si aspetta.
- Per le route SSE, verifica che il client si colleghi all'URL corretto e che l'handler restituisca
{"sse": true}.
Vedi anche
- 24. Componenti server Web UI - UI server orientata ai componenti, fragment, aggiornamenti live e
ui.* - Server REST API - Progettazione delle route API, middleware, validazione e policy
- Sviluppo full-stack con MALDA - Guida all'architettura per mescolare pagine, API e UI nel browser