Dans le monde actuel axé sur le web, les serveurs traitent un nombre impressionnant de requêtes. Il est essentiel d’analyser, de compter, d’interpréter et de réacheminer efficacement ces requêtes, en particulier lorsque l’on applique le modèle MVC.
Avec l’introduction des gestionnaires de requêtes HTTP sur le serveur HTTP 4D, vous pouvez déclencher une logique métier spécifique basée sur les requêtes reçues.
Les principaux avantages sont:
- Avoir plus de granularité quant à l’implémentation du code gérant les requêtes reçues. Cette logique métier peut être implémentée dans plusieurs classes. Oubliez les gros Case of dans la méthode base On Web Connection database.
- Gérer une redirection sur une page Qodly ce qui ouvre de nouvelles perspectives quant à l’extension sur le web d’une application 4D.
Cette fonctionnalité puissante ouvre donc de nombreuses possibilités, comme le détaille cet article de blog. Continuez cette intéressante lecture pour découvrir des exemple concrets.
Avec les gestionnaires de requêtes HTTP, vous pouvez définir autant de gestionnaires que nécessaire, adaptés à des modèles d’URL et à des verbes HTTP spécifiques.
Avant de rentrer dans les détails, procédons à une analyse comparative montrant la valeur ajoutée de cette fonctionnalité.
analyse comparative
| Puis-je: | Avec la méthode base On Web Connection | Avec les HTTP Handlers |
| Répartir mon code gérant les requêtes sur plusieurs classes | Non | Oui |
| Rediriger l’utilisateur vers une page Qodly | Non | Oui |
| Forcer l’utilisateur à s’authentifier même pour requêter une ressource web existante (une page html) | Non | Oui |
Pour illustrer ceci, analysons ces exigences:
- Tant que l’utilisateur n’est pas authentifié, il est re dirigé vers la page d’authentification
- Seules les pages html existantes du répertoire /pages sont visibles. Si des pages inexistantes sont requêtées, une page Ressource non trouvée est affichée
- Si d’autres ressources sont requêtées, une page Non autorisée est affichée
- La requête /pages affiche la page /pages/welcome.html
- Les pages html autorisées offrent des fonctionnalités upload / download
avec les méthodes base On Web Authentication / Connection
la methode On Web Authentication
Case of
// The user is not authenticated
: (Session.isGuest())
WEB SEND HTTP REDIRECT("/authentication/authentication.html")
return False
Else
return True
End case
la methode On Web connection
#DECLARE($url : Text)
Case of
: ($url="/pages")
WEB SEND HTTP REDIRECT("/pages/welcome.html")
: (Position("/fileUpload/"; $url)=1)
//Handle the file upload business logic
: (Position("/fileDownload"; $url)=1)
//Handle the file download business logic
// The requested resource is not an html page of the pages folder
: Not(Match regex("/pages/[a-z]*[0-9]*[.]html"; $url))
WEB SEND HTTP REDIRECT("/error/notAuthorized.html")
Else
WEB SEND HTTP REDIRECT("/error/notFound.html")
End case
C’est juste un petit exemple de code montrant que la méthode base On Web Connection database method peut devenir complexe, et donc difficile à maintenir.
avec les http request handlers
Les exemples ci-dessous montrent comment facilement associer des patterns d’URL à une loge métier spécifique et comment structurer ce code dans des classes.
Vous verrez aussi comment gérer la redirection sur des pages Qodly et comment re diriger l’utilisateur sur une page d’authentification (même en requêtant une ressource existante).
les gestionnaires de requetes pourquoi?
Les gestionnaires de requêtes permettent d’envisager plusieurs scénarios:
- utiliser une URL comme fournisseur de ressource (téléchargement de fichiers)
- utiliser une URL comme outil d’envoi de fichier (poster sur le server des fichiers en appelant une URL)
- gérer la redirection sur des pages spécifiques selon un contexte utilisateur (utilisateur authentifié ou non, page non trouvée, présence de privileges dans la session … etc)
comment configurer un gestionnaire de requêtes HTTP
Les gestionnaires de requêtes HTTP doivent être configurés dans le fichier HTTPHandlers.json du dossier Project/Sources.
Ce fichier contient une collection d’objets au format JSON. Chaque objet fait référence à un gestionnaire de requêtes avec les informations suivantes :
- le modèle d’URL à traiter
- le verbe utilisé par l’URL
- le couple [classe de singleton + fonction] où le code du gestionnaire de requête est implémenté
Exemple de fichier
Fichier HTTPHandlers.json :
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
Question: Qu’est-ce que cela signifie ?
Réponse: Cela signifie que lorsqu’une requête commençant par /start/ avec un verbe GET ou POST est reçue sur le serveur, la fonction gettingStarted du singleton GeneralHandling est exécutée.
Comment implémenter le code du gestionnaire de requêtes ?
La classe singleton mentionnée ci-dessus doit être partagée.
Entrée : une instance de la nouvelle classe 4D.IncomingMessage
La demande est reçue sur le serveur sous la forme d’une instance d’objet de la nouvelle classe 4D.IncomingMessage.
Les informations suivantes sont disponibles
- l’url complète de la requête
- les parties de l’url
- le verbe de la requête
- les en-têtes de la requête
- les paramètres mis dans l’URL (s’il y en a)
- le corps de la requête (le cas échéant)
Ensuite, le gestionnaire de la requête peut utiliser toutes ces informations pour déclencher la logique métier appropriée.
Résultat : une instance de la classe 4D.OutgoingMessage.
Si nécessaire, le gestionnaire de la demande peut renvoyer un objet de la classe 4D.OutgoingMessage, c’est-à-dire un contenu web complet prêt à être traité par un navigateur (par exemple, le contenu d’un fichier).
un exemple simple pour commencer
Avec le même fichier HTTPHandlers.json que ci-dessus :
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
La requête http://127.0.0.1/start/example?param=demo&name=4D est exécutée avec un verbe GET dans un navigateur. Elle est traitée par la fonction gettingStarted() de la classe singleton GeneralHandling ci-dessous :
return $resultshared singleton Class constructor()
Function gettingStarted($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $body : Text
$body:="Called URL: "+$request.url+"\n"
$body+="The parameters are received as an object:"+"\n"+JSON Stringify($request.urlQuery; *)+"\n"
$body+="The verb is: "+$request.verb+"\n"
$body+="There are "+String($request.urlPath.length)+" url parts - Url parts are: "+$request.urlPath.join(" - ")+"\n"+"\n"
$result.setBody($body)
$result.setHeader("Content-Type"; "text/plain")
return $result
La requête est reçue sur le serveur sous la forme de $request (une instance d’objet de la nouvelle classe 4D.IncomingMessage ).
Cet objet $request contient les propriétés suivantes:
- url (String) – URL de la demande
- urlQuery (Objet) – Paramètres de la demande.
- verb (String) – Verbe
- urlPath (collection de String) – Parties de l’URL de la demande
Voici la réponse :

comment gérer un corps dans la demande
La nouvelle classe 4D.IncomingMessage fournit des fonctions permettant d’obtenir les en-têtes et le corps de la requête.
exemple
Exécutons un exemple simple pour télécharger un fichier sur le serveur.
Le fichier HTTPHandlers.json :
[
{
"class": "UploadFile",
"method": "uploadFile",
"regexPattern": "/putFile",
"verbs": "POST"
}
]
Notez que le modèle d’URL est donné sous forme d’expression régulière avec la propriété regexPattern.
La requête http://127.0.0.1:8044/putFile?fileName=testFile est exécutée avec un verbe POST et un contenu de fichier dans son corps.
La classe singleton UploadFile:
Function uploadFile($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $response:=4D.OutgoingMessage.new()
var $body:="Not supported file"
var $fileName; $fileType : Text
var $file : 4D.File
var $picture : Picture
var $created : Boolean
//The file name is given as parameter in the URL
$fileName:=$request.urlQuery.fileName
// The header "Content-Type" provides the format of the body
$fileType:=$request.getHeader("Content-Type")
Case of
// The body contains a pdf file
: ($fileType="application/pdf")
$file:=File("/PACKAGE/Files/"+$fileName+".pdf")
$created:=$file.create()
// The getBlob() function returns the body of the request as a Blob
$file.setContent($request.getBlob())
$body:="Upload OK - File size: "+String($file.size)
// The body contains a jpg image
: ($fileType="image/jpeg")
$file:=File("/PACKAGE/Files/"+$fileName+".jpg")
// The getPicture() function returns the body of the request as a Picture
$picture:=$request.getPicture()
WRITE PICTURE FILE($file.platformPath; $picture)
$body:="Upload OK - Image size: "+String($file.size)
End case
$response.setBody($body)
$response.setHeader("Content-Type"; "TEXT/plain")
return $response
Le nom du fichier est donné en tant que paramètre (fileName) dans l’URL. Il est reçu dans l’objet urlQuery reçu par la requête.
Fonctions permettant d’obtenir les en-têtes et le corps de la requête
Dans l’exemple ci-dessus, notez la fonction getHeader() qui renvoie un en-tête donné de la requête. La classe 4D.IncomingMessage offre également une propriété headers (Object) contenant tous les en-têtes de la requête.
L’en-tête Content-Type fournit le format du corps reçu. Dans cet exemple, seuls les formats pdf et jpeg sont traités.
Notez les fonctions getBlob() et getPicture() sur l’objet $request. Elles fournissent le contenu du corps dans le format approprié qui correspond à l’en-tête Content-Type.
Voir la documentation pour plus de détails sur ces fonctions.
Une fonction getText() est également disponible et fournit le corps de la requête sous forme de chaîne de caractères (si elle a été envoyée sous forme de chaîne)
Si le corps de la requête a été envoyé sous la forme d’une représentation JSON valide, la fonction getJSON() fournit sa résolution avec le type correct (par exemple, Object, Collection, String, …).
gérer la redirection
Le gestionnaire de requêtes est également capable de rediriger vers une page spécifique en renvoyant une instance de la classe 4D.OutgoingMessage . L’en-tête Location doit être utilisé pour indiquer la page à rediriger.
Le statut HTTP 3xx indique que le client doit prendre des mesures supplémentaires pour compléter la demande.
Exécutons ce scénario :
– L’utilisateur peut visualiser toutes les pages html du dossier WebFolder/pages une fois qu’il est authentifié. Tant que l’utilisateur n’est pas authentifié, il est redirigé vers une page d’authentification.
– Si la page demandée ne se trouve pas dans ce dossier, une page » Non trouvé » est affichée.
– Si l’utilisateur demande une page dans un sous-dossier du dossier /pages, une page Non autorisée est servie.
Le fichier HTTPHandlers.json :
[
{
"class": "PagesHandling",
"method": "handle",
"regexPattern": "/pages/"
}
]
La classe singleton PagesHandling:
shared singleton Class constructor()
Function handle($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $file : 4D.File
//The user is not authenticated
If (Session.isGuest())
$result.setHeader("Location"; "/authentication/Authentication.html")
$result.setStatus(307)
Else
//The URL is an html page in the /pages folder
If (($request.urlPath.length=2) && (Position(".html"; $request.url)#0))
$file:=File("/PACKAGE/WebFolder"+$request.url)
//The pages exists
If ($file.exists)
$result.setBody($file.getContent())
$result.setHeader("Content-Type"; "text/html")
$result.setStatus(200)
//The pages does not exist
Else
$result.setHeader("Location"; "/error/NotFound.html")
$result.setStatus(307)
End if
//The URL is NOT a an html page in the /pages folder
Else
$result.setHeader("Location"; "/error/NotAuthorized.html")
$result.setStatus(307)
End if
End if
return $result
Notez que le gestionnaire de requêtes a accès à l’objet Session, ce qui permet une logique métier plus complexe (vérification de la présence de certains privilèges, utilisation de l’objet partagé Session.storage ).
Comparez cet exemple avec celui donné au début de cet article (redirection gérée par la méthode base On Web Connection database). Vous constaterez que grâce aux patterns d’URLs gérés dans le fichier HTTPHandlers.json et à la propriété urlPath de la classe 4D.IncomingMessage, plus besoin de tester des expressions complexes pour l’URL.
comment re diriger sur une page qodly ?
Indiquez l’URL de rendering de votre page Qodly dans le header Location.
$result.setHeader("Location"; "https://myQodlyApp/$lib/renderer/?w=Authentication")
Téléchargez le HDI pour vous exercer avec les gestionnaires de requêtes et n’attendez plus pour passer au mode projet avec ses classes et autres fonctionnalités puissantes.
