HTTP Request handler
Por defecto, las peticiones HTTP recibidas por el servidor web 4D se gestionan a través de funciones de procesamiento integradas o del servidor REST.
In addition, 4D supports the implementation of custom HTTP Request handlers, allowing you to intercept specific incoming HTTP requests and process them using your own code.
Cuando un manejador de peticiones HTTP personalizado intercepta una solicitud, se procesa directamente y no hay otras funcionalidades de procesamiento (por ejemplo, son llamados métodos base On Web authentication o On Web connection.
Custom HTTP request handlers meet various needs, including:
- using a given URL as a resource provider or a file-uploading box (to download or upload various files),
- redirecting on specific pages according to a context (user authenticated, privileges granted...),
- gestionar una autenticación a través de oAuth 2.0.
Requisitos
Se soportan gestores de solicitudes HTTP personalizados:
- cuando las sesiones escalables están habilitadas,
- with the main Web Server only (HTTP Request handlers that may have been defined in Web Servers of components are ignored).
Por defecto por razones de seguridad, el acceso externo al datastore no está permitido en 4D. You need to configure the ORDA privileges to allow HTTP requests.
Archivo HTTPHandlers.json
Define sus manejadores de petición HTTP personalizados en un archivo de configuración llamado HTTPHandlers.json almacenado en la carpeta Project/Sources
.
This file contains all listened URL patterns, the handled verbs, and the code to be called. Handlers are provided as a collection in JSON format.
At runtime, the first pattern matching the URL is executed, the others are ignored.
Este es un ejemplo del contenido de un archivo HTTPHandlers.json:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
This handler declaration can be read as: when any request starting by /start/
with a GET
or POST
verb is received by the server, the gettingStarted
function of the GeneralHandling
singleton is executed.
You must restart the Web server so that modifications made in this file are taken into account.
Definición del gestor
A handler is defined by:
- a listened URL pattern
- a function and its class where the code is implemented to handle the listened URL pattern
- the verbs with which the URL can be called to trigger the handler
The handler identifier is the couple [pattern + a verb among the verbs list].
Patrones de la URL
URL patterns can be given as prefixes or using regular expressions.
-
To declare a prefix pattern, use the "pattern" property name in the HTTPHandlers.json file. Prefixes are considered as regular expressions already containing starting and ending
/
.
Ej:"pattern": "docs"
o"pattern": "docs/invoices"
-
To declare a regular expression pattern, use the "regexPattern" property name in the HTTPHandlers.json file. Los modelos de expresiones regulares se manejan directamente. Ej:
"regexPattern" : "/docs/.+/index\.html"
"Pattern" and "regexPattern" properties cannot be used in the same handler definition (in this case, only the "regexPattern" property is taken into account).
Concordancia de modelos
URL patterns are triggered in the given order:
- se ejecuta el primer modelo coincidente
- the following patterns are not executed even if they match the URL
As a consequence, you need to apply a accurate strategy when writing your handlers: the most detailed patterns must be written before the more general patterns.
[
{
"class": "InvoiceslHandling",
"method": "handleTheInvoice",
"regexPattern": "/docs/invoices/details/theInvoice",
"verbs": "GET"
},
{
"class": "InvoiceslHandling",
"method": "handleUnauthorizedVerbs",
"regexPattern": "/docs/invoices/details/theInvoice",
"comment": "This handler is triggered for all verbs except GET (handled above)"
},
{
"class": "DocsHandling",
"method": "handleDocs",
"regexPattern": "/docs",
"comment": "This handler is triggered for all the verbs"
}
]
Patrones prohibidos
URL patterns matching 4D built-in HTTP processing features are not allowed in custom HTTP handlers. For example, the following patterns cannot be handled:
/4DACTION
/rest
/$lib/renderer
/$shared
Clase y método
You declare the code to be executed when a defined URL pattern is intercepted using the "class" and "method" properties.
- "class": class name without
cs.
, e.g. "UsersHandling" for thecs.UsersHandling
user class. Debe ser una clase compartida y singleton. - "method": class function belonging to the class.
Ver abajo para obtener información sobre el código del gestor de peticiones.
Verbs
You can use the "verbs" property in the handler definition to declare HTTP verbs that are supported in incoming requests for this handler. A request that uses a verb that is not explicitely allowed is automatically rejected by the server.
You can declare several verbs, separated by a comma. Verb names are not case sensitive.
Ej: "verbs" : "PUT, POST"
No control is done on verb names. Se pueden utilizar todos los nombres.
By default, if the "verbs" property is not used for a handler, all HTTP verbs are supported in incoming requests for this handler (except those possibly used beforehand in a more detailed pattern, as shown in the example above).
El verbo HTTP también puede ser evaluado utilizando la propiedad .verb
dentro del código del manejador de peticiones para ser aceptado o rechazado.
Ejemplo
He aquí un ejemplo detallado de un archivo HTTPHandlers.json:
[
{
"clase": "GeneralHandling",
"method": "handle",
"pattern": "info", //prefijo URL
"verbs": "GET"
},
{
"class": "UsersHandling",
"method": "manageAccount",
"pattern": "userAccount/update", //prefijo URL
"verbs": "PUT,POST"
},
{
"class": "FinancialHandling",
"method": "handleInvoices",
"regexPattern": "/docs/invoices/(past|today)", //prefijo de URL dado como regex
"verbs": "GET"
},
{
"class": "DocsHandling",
"method": "handleDocs",
"regexPattern": "/docs/myPage.html", //prefijo de URL dado como regex
"verbs": "GET"
},
{
"class": "InvoicesHandling",
"method": "handleTheInvoice",
"pattern": "docs/invoices/details/theInvoice", // La URL más específica primero
"verbs": "GET,POST"
},
{
"class": "InvoicesHandling",
"method": "handleDetails",
"pattern": "docs/invoices/details", // Las URL generales después de
"verbs": "GET"
},
{
"class": "InvoicesHandling",
"method": "handleInvoices", // Las URL generales después de
"pattern": "docs/invoices",
"verbs": "GET"
}
]
En este ejemplo, debe implementar las siguientes funciones:
- funciónhandle en la clase *GeneralHandling
- manageAccount en la clase UsersHandling
- handleInvoices en la clase FinancialHandling
- handleDocs en la clase DocsHandling
- handleTheInvoice / handleDetails / handleInvoices en la clase InvoicesHandling
Examples of URLs triggering the handlers:
IP:port/info/
con un verbo GET
IP:port/info/general
con un verbo GET
IP:port/userAccount/update/
con un verbo POST
IP:port/userAccount/update/profile
con un verbo POST
IP:port/docs/invoices/past
con un verbo GET
IP:port/docs/invoices/today/latest
con un verbo GET
IP:port//docs/myPage.html
con un verbo GET
IP:port//docs/invoices/
con un verbo GET, llama a la función handleInvoices (clase InvoicesHandling)
IP:port//docs/invoices/details/
con un verbo GET, llama a la función handleDetails (clase InvoicesHandling)
IP:port//docs/invoices/details/theInvoice/xxxxxx
con un verbo GET, llama a la función handleTheInvoice (clase InvoiceslHandling)
Código del gestor de peticiones
Function configuration
The HTTP Request handler code must be implemented in a function of a Shared singleton class.
If the singleton is missing or not shared, an error "Cannot find singleton" is returned by the server. If the class or the function defined as handler in the HTTPHandlers.json file is not found, an error "Cannot find singleton function" is returned by the server.
Request handler functions are not necessarily shared, unless some request handler properties are updated by the functions. En este caso, necesita declarar sus funciones con la palabra clave 'shared'.
Entrada: una instancia de la clase 4D.IncomingMessage
Cuando una solicitud ha sido interceptada por el manejador, se recibe en el servidor como una instancia de la clase 4D.IncomingMessage.
All necessary information about the request are available in this object, including the request url, verb, headers, and, if any, parameters (put in the URL) and body.
Then, the request handler can use this information to trigger appropriate business logic.
Output: an instance of the 4D.OutgoingMessage class
The request handler can return an object instance of the 4D.OutGoingMessage class, i.e. some full web content ready for a browser to handle, such as a file content.
Ejemplo
La clase 4D.IncomingMessage ofrece funciones para obtener los encabezados y el cuerpo de la solicitud.
He aquí un ejemplo sencillo para cargar un archivo en el servidor.
El archivo HTTPHandlers.json:
[
{
"class": "UploadFile",
"method": "uploadFile",
"regexPattern": "/putFile",
"verbs": "POST"
}
]
The called URL is: http://127.0.0.1:8044/putFile?fileName=testFile
The binary content of the file is put in the body of the request and a POST verb is used. El nombre del archivo se da como parámetro (fileName) en la URL. Se recibe en el objeto urlQuery
en la petición.
//UploadFile class
shared singleton Class constructor()
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
$fileName:=$request.urlQuery.fileName
$fileType:=$request.getHeader("Content-Type")
Case of
: ($fileType="application/pdf")
$file:=File("/PACKAGE/Files/"+$fileName+".pdf")
$created:=$file.create()
$file.setContent($request.getBlob())
$body:="Upload OK - File size: "+String($file.size)
: ($fileType="image/jpeg")
$file:=File("/PACKAGE/Files/"+$fileName+".jpg")
$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
Ver también
Perfect mastery of your back end business logic thanks to HTTP requests handlers (blog post)