📦 Contesto - oCtx¶
Quando HIX esegue un middleware, passa sempre un singolo parametro: oCtx.
È il contesto della request - un'istanza di THixContext che raggruppa tutto
ciò che un middleware ha bisogno per ispezionare la request, comunicare con gli altri anelli della catena di middleware
e decidere cosa deve succedere dopo.
FUNCTION MW_ApiKey( oCtx )
// oCtx è il contesto - vive per tutta la catena di middleware
// e scompare quando la request termina
RETURN .T.
Perché esiste oCtx invece di un semplice oReq?¶
Un middleware raramente agisce da solo. In una catena tipica (rate limit → JWT → ruoli → action), ogni middleware ha bisogno di condividere informazioni con i successivi: il payload JWT, la sessione dell'utente, un flag di audit...
oCtx è quello "spazio condiviso". È il vassoio che si passa di mano in mano
per tutta la catena, e quando arriva all'action della route resta disponibile.
Proprietà principali¶
| Proprietà | Tipo | Descrizione |
|---|---|---|
oCtx:oReq |
THixRequest |
Oggetto request della request corrente. |
oCtx:hData |
Hash | Dizionario libero per condividere dati tra middleware. |
oCtx:lHandled |
Logico | Impostalo a .T. quando il middleware ha già risposto. |
oCtx:cScope |
Stringa | Metadati liberi assegnati alla route (accessibile dai MW). |
oCtx:cOnFail |
Stringa | URL di redirect se il middleware ritorna .F. (opzionale). |
oCtx:oReq - la request¶
È l'oggetto THixRequest della request corrente. Possiamo leggere header,
cookie, body, parametri di query, ecc. da lì:
LOCAL cKey := oCtx:oReq:Header( "X-Api-Key", "" )
LOCAL cSid := oCtx:oReq:Cookie( "hix_sess", "" )
LOCAL cIp := oCtx:oReq:IP()
Alternativa consigliata - helper U*¶
HIX collega automaticamente la request al thread corrente prima di eseguire ogni
middleware, quindi gli helper U* funzionano anche dentro il middleware,
e sono di solito più brevi e coerenti con il codice delle action:
FUNCTION MW_ApiKey( oCtx )
// Entrambe le righe sono equivalenti:
LOCAL cKey := oCtx:oReq:Header( "X-Api-Key", "" )
LOCAL cKey := UHeader( "X-Api-Key", "" ) // più breve e leggibile
IF cKey != "chiave-segreta-123"
USendError( 401, "API Key non valida" )
RETURN .F.
ENDIF
RETURN .T.
Stile con oCtx:oReq |
Stile con U* |
|---|---|
oCtx:oReq:Header( c, x ) |
UHeader( c, x ) |
oCtx:oReq:Cookie( c, x ) |
UCookie( c, x ) |
oCtx:oReq:Body() |
UBody() |
oCtx:oReq:IP() |
UIP() |
oCtx:oReq:Method() |
UMethod() |
Scegli lo stile che preferisci - HIX non ne impone uno. La convenzione attuale è
usare gli U* dentro action e middleware per mantenere il codice conciso.
oCtx:hData - condividere dati tra middleware¶
hData è un hash libero che si propaga attraverso l'intera catena di middleware e
arriva intatto all'action della route. È il canale ufficiale per passare
informazioni tra anelli.
Chiavi convenzionali già usate dai middleware di sistema:
| Chiave | Impostata da | Contenuto |
|---|---|---|
oCtx:hData["jwt"] |
HixMwJwt |
Hash con il payload del token JWT verificato. |
oCtx:hData["session"] |
HixMwSession |
Hash con i dati della sessione attiva. |
oCtx:hData["_sid"] |
HixMwSession |
ID della sessione attiva. |
oCtx:hData["user"] |
Middleware di auth | Oggetto/hash dell'utente autenticato. |
Esempio - un middleware di ruoli che legge ciò che HixMwJwt ha già lasciato:
FUNCTION MW_RequireAdmin( oCtx )
LOCAL hJwt := hb_HGetDef( oCtx:hData, "jwt", NIL )
IF hJwt == NIL .OR. hb_HGetDef( hJwt, "role", "" ) != "admin"
USendError( 403, "Solo admin" )
RETURN .F.
ENDIF
RETURN .T.
Puoi aggiungere le tue chiavi senza toccare nulla del sistema:
oCtx:lHandled - "Ho già risposto, non eseguire l'action"¶
Quando un middleware decide di interrompere la catena (rifiutare la request) deve:
- Inviare la risposta al client.
- Impostare
oCtx:lHandled := .T.così il dispatcher sa che la risposta è già stata inviata e non esegue nient'altro. - Restituire
.F..
Se usi gli helper USendError / USendJson / URedirect, segnano già
lHandled internamente - non devi farlo manualmente.
FUNCTION MW_ApiKey( oCtx )
IF UHeader( "X-Api-Key", "" ) != "chiave-segreta-123"
USendError( 401, "API Key non valida" ) // segna lHandled
RETURN .F.
ENDIF
RETURN .T.
oCtx:cScope - metadati della route¶
Quando registri una route puoi allegare una stringa libera come scope. Quel
valore arriva al middleware tramite oCtx:cScope e serve per variare il comportamento
in base al "gruppo logico" a cui appartiene la route.
oSrv:AddRouteGet( "admin.users", "/admin/users", 'users.prg', "MW_Log", "admin" )
oSrv:AddRouteGet( "api.stats", "/api/stats", 'stats.prg', "MW_Log", "public" )
FUNCTION MW_Log( oCtx )
IF oCtx:cScope == "admin"
l( "[AUDIT] " + UMethod() + " " + UPath() + " da " + UIP() )
ENDIF
RETURN .T.
oCtx:cOnFail - redirect di fallback¶
Route a cui reindirizzare automaticamente quando il middleware ritorna .F.
(opzionale). Utile, ad esempio, per mandare a /login qualsiasi route che fallisce
l'autenticazione senza ripetere la logica in ogni middleware.
Riepilogo¶
oCtxè il contesto della request, l'unico parametro ricevuto da ogni middleware.oCtx:oReqfornisce accesso alla request; in alternativa puoi usare gli helperU*.oCtx:hDataè l'hash condiviso tra middleware e l'action.oCtx:lHandled := .T.quando interrompi la catena; gli helperUSend*lo fanno già.oCtx:cScopesono metadati liberi della route.oCtx:cOnFaildefinisce l'URL di redirect se il middleware rifiuta.