En el mundo web actual, los servidores procesan un número abrumador de peticiones. Analizar, contar, interpretar y redirigir eficientemente estas solicitudes es esencial, especialmente cuando se aplican los principios MVC.
Con la introducción de HTTP Request Handlers en el servidor HTTP 4D, puede activar lógica de negocio específica basada en las peticiones recibidas. Esta poderosa funcionalidad abre muchas posibilidades, como se detalla en esta entrada de blog.
Con HTTP Request Handlers, puede definir tantos handlers como necesite, adaptados a patrones URL y verbos HTTP específicos. Este enfoque ofrece una granularidad mucho mayor que los métodos tradicionales de autenticación en la web y conexión en la web a bases de datos, ahorrándole la implementación de extensas declaraciones Case of.
¿por qué los Gestores de peticiones?
El manejo de gestores de peticiones conduce a varios escenarios como:
- utilizar una URL dada como proveedor de recursos (por ejemplo, descargar varios archivos llamando a una URL específica)
- utilizar una URL dada como caja de carga de archivos (por ejemplo, cargar varios archivos llamando a una URL específica)
- gestionar la redirección en páginas específicas en función de un contexto empresarial (por ejemplo, usuario autenticado o no, página no encontrada, privilegios concedidos o no… etc.)
- conservar las estadísticas y cualquier información relacionada con una solicitud recibida
- gestionar una autenticación mediante oAuth 2.0
cómo configurar un gestor de peticiones HTTP
Los manejadores de peticiones HTTP deben ser configurados en el archivo HTTPHandlers.json en la carpeta Project/Sources.
Este archivo contiene una colección de objetos en formato JSON. Cada objeto se refiere a un manejador de peticiones con la siguiente información:
- el patrón de URL a manejar
- el verbo utilizado por la URL
- la [clase singleton + función] donde se implementa el código del manejador de peticiones
ejemplo
Archivo HTTPHandlers.json:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
Pregunta: ¿Qué significa?
Respuesta: Significa que cuando se recibe en el servidor cualquier petición que empiece por /start/ con un verbo GET o POST, se ejecuta la función gettingStarted del singleton GeneralHandling.
cómo implementar el código del manejador de peticiones
La clase singleton mencionada anteriormente debe ser compartida.
Entrada: una instancia de la nueva clase 4D.IncomingMessage
La petición se recibe en el servidor como una instancia del objeto de la nueva clase 4D.IncomingMessage.
Se dispone de la siguiente información
- la url completa de la petición
- las partes de la url
- el verbo de la petición
- los encabezados de la petición
- los parámetros introducidos en la URL (si los hay)
- el cuerpo de la solicitud (si existe)
A continuación, el gestor de peticiones puede utilizar toda esta información para activar la lógica de negocio apropiada.
Salida: una instancia de la clase 4D.OutgoingMessage
Si es necesario, el gestor de peticiones puede devolver una instancia de la clase 4D.clase OutgoingMessage, es decir, algún contenido web completo listo para que un navegador lo maneje (por ejemplo, como contenido de archivos).
un ejemplo sencillo para empezar
Con el mismo archivo HTTPHandlers.json que arriba:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
La petición http://127.0.0.1/start/example?param=demo&name=4D se ejecuta con un verbo GET en un navegador. Es manejada por la función gettingStarted() de la clase singleton GeneralHandling a continuación:
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 petición se recibe en el servidor como $request (un objeto instancia de la nueva clase 4D.IncomingMessage ).
Este objeto $request contiene las propiedades:
- url (String) – URL de la petición
- urlQuery (Object) – Parámetros de la petición.
- verb (Cadena) – Verbo
- urlPath (colección de Strings) – Partes de la URL de la petición
Aquí está la respuesta:
cómo manejar un cuerpo en la petición
La nueva clase 4D.IncomingMessage ofrece algunas funciones para obtener los encabezados y el cuerpo de la petición.
ejemplo
Vamos a ejecutar un ejemplo sencillo para subir un fichero al servidor.
El archivo HTTPHandlers.json:
[
{
"class": "UploadFile",
"method": "uploadFile",
"regexPattern": "/putFile",
"verbs": "POST"
}
]
Observe que el patrón de URL se da como una expresión regular con la propiedad regexPattern.
La petición http://127.0.0.1:8044/putFile?fileName=testFile se ejecuta con un verbo POST y un contenido de archivo en su cuerpo.
La clase 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
El nombre del fichero se da como parámetro (fileName) en la URL. Se recibe en el objeto urlQuery en la petición.
Funciones para obtener lOs encabezados y el cuerpo de la petición
En el ejemplo anterior, observe la función getHeader() que devuelve un encabezado determinado de la petición. La clase 4D.IncomingMessage también ofrece una propiedad headers (Object) que contiene todos los encabezados de la petición.
El encabezado Content-Type proporciona el formato del cuerpo recibido. En este ejemplo, sólo se manejan los formatos pdf y jpeg.
Observe las funciones getBlob() y getPicture() en el objeto $request. Proporcionan el contenido del cuerpo en el formato apropiado que coincide con el encabezado Content-Type.
Consulte la documentación para más detalles sobre estas funciones.
La función getText() también está disponible y ofrece el cuerpo de la petición como una cadena (si se ha enviado como una cadena).
Si el cuerpo se ha dado como una representación JSON válida, la función getJSON() proporciona su resolución con el tipo correcto (por ejemplo, Object, Collection, String, …).
manejar la redirección
El manejador de peticiones también es capaz de redirigir a una página específica devolviendo una instancia de la clase4D.OutgoingMessage. El encabezado Location debe utilizarse para indicar la página a redirigir.
El valor de estado HTTP 3xx indica que el cliente debe realizar una acción adicional para completar la solicitud.
Vamos a ejecutar este escenario:
– El usuario puede ver todas las páginas html de la carpeta WebFolder/pages una vez autenticado. Mientras el usuario no esté autenticado, se le redirige a una página de autenticación.
– Si la página solicitada no se encuentra en esta carpeta, se sirve una página No encontrada.
– Si el usuario pide una página en una subcarpeta de la carpeta /pages, se sirve una página No autorizada.
El archivo HTTPHandlers.json:
[
{
"class": "PagesHandling",
"method": "handle",
"regexPattern": "/pages/"
}
]
La clase 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
Observe que el manejador de peticiones tiene acceso al objeto Session que permite una lógica de negocio más compleja (comprobar la presencia de algunos privilegios, utilizar el objeto compartido Session.storage ).
Descarga el IDH para practicar el manejo de las peticiones HTTP y no espere más para entrar en el mundo del modo proyecto proponiendo clases y otras poderosas funcionalidades.