No mundo atual, orientado para a Web, os servidores processam um número avassalador de pedidos. Analisar eficientemente, contar, interpretar e redirecionar esses pedidos é essencial, especialmente quando se aplica os princípios MVC.
Com a introdução de HTTP Request Handlers no 4D HTTP Server, é possível acionar uma lógica comercial específica baseada nos pedidos recebidos. Essa caraterística poderosa abre muitas possibilidades, como detalhado nesse post do blog.
Com HTTP Request Handlers, é possível definir quantos handlers forem necessários, adaptados a padrões específicos de URL e verbos HTTP. Esta abordagem fornece uma granularidade muito maior do que os métodos tradicionais de base de dados On Web Authentication e On Web Connection, poupando-o à implementação de extensas declarações Case of.
manipuladores de pedidos por quê?
O tratamento de request handlers conduz a vários cenários, tais como
- utilizar um determinado URL como fornecedor de recursos(por exemplo, descarregar vários arquivos chamando um URL específico)
- utilizar um determinado URL como uma caixa de carregamento de arquivos(por exemplo, carregar vários arquivos chamando um URL específico)
- tratar o redirecionamento em páginas específicas de acordo com um contexto comercial(por exemplo, usuário autenticado ou não, página não encontrada, privilégios concedidos ou não … etc.)
- manter estatísticas e quaisquer informações relacionadas com um pedido recebido
- tratar uma autenticação via oAuth 2.0
como configurar um gestor de pedidos HTTP
Os manipuladores de pedidos HTTP devem ser configurados no ficheiro HTTPHandlers.json na pasta Project/Sources.
Este arquivo contém uma coleção de objetos em formato JSON. Cada objeto refere-se a um manipulador de solicitação com as seguintes informações:
- o padrão de URL a ser tratado
- o verbo usado pelo URL
- a [classe singleton + função] onde o código do request handler é implementado
exemplo
arquivo HTTPHandlers.json:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
Pergunta: O que é que isto significa?
Resposta: Isto significa que quando qualquer pedido que comece por /start/ com um verbo GET ou POST é recebido no servidor, a função gettingStarted do singleton GeneralHandling é executada.
como implementar o código do manipulador de pedidos
A classe singleton acima referida deve ser partilhada.
Entrada: uma instância da nova classe 4D.IncomingMessage
O pedido é recebido no servidor como uma instância de objeto da nova classe 4D.IncomingMessage.
As seguintes informações estão disponíveis:
- a url completa do pedido
- as partes da url
- o verbo do pedido
- os cabeçalhos do pedido
- os parâmetros colocados no URL (se existirem)
- o corpo do pedido (se existir)
Então, o manipulador do pedido pode usar toda essa informação para acionar a lógica comercial apropriada.
Saída: uma instância da classe 4D.OutgoingMessage
Se necessário, o manipulador do pedido pode retornar uma instância do objeto da classe 4D.OutgoingMessage, ou seja., algum conteúdo web completo pronto para ser manipulado por um navegador (por exemplo, como conteúdo de arquivo).
um exemplo simples para começar
Com o mesmo arquivo HTTPHandlers.json como acima:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
O pedido http://127.0.0.1/start/example?param=demo&name=4D é executado com um verbo GET num browser. Ele é tratado pela função gettingStarted() da classe singleton GeneralHandling abaixo:
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
O pedido é recebido no servidor como $request (uma instância de objeto da nova classe 4D.IncomingMessage ).
Este objeto $request contém as propriedades:
- url (String) – URL do pedido
- urlQuery (Object) – Parâmetros do pedido.
- verb (String) – Verbo
- urlPath (coleção de Strings) – Partes do URL do pedido
Aqui está a resposta:
como tratar um corpo no pedido
A nova classe 4D.IncomingMessage fornece algumas funções para obter os cabeçalhos e o corpo do pedido.
exemplo
Vamos executar um exemplo simples para carregar um ficheiro no servidor.
O arquivo HTTPHandlers.json:
[
{
"class": "UploadFile",
"method": "uploadFile",
"regexPattern": "/putFile",
"verbs": "POST"
}
]
Observe que o padrão de URL é fornecido como uma expressão regular com a propriedade regexPattern.
O pedido http://127.0.0.1:8044/putFile?fileName=testFile é executado com um verbo POST e um conteúdo de arquivo no seu corpo.
A 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
//O nome do arquivo é dado como parâmetro na URL
$fileName:=$request.urlQuery.fileName
// O cabeçalho "Content-Type" oferece o formato do corpo
$fileType:=$request.getHeader("Content-Type")
Case of
// o corpo contém um arquivo pdf
: ($fileType="application/pdf")
$file:=File("/PACKAGE/Files/"+$fileName+".pdf")
$created:=$file.create()
// A função getBlob() retorna o corpo da petição como um Blob
$file.setContent($request.getBlob())
$body:="Upload OK - File size: "+String($file.size)
// O corpo contém uma imagem jpg
: ($fileType="image/jpeg")
$file:=File("/PACKAGE/Files/"+$fileName+".jpg")
// A função getPicture() retorna o corpo da petição como uma Imagem
$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
O nome do arquivo é fornecido como parâmetro(fileName) no URL. É recebido no objeto urlQuery no pedido.
Funções para obter os cabeçalhos e o corpo do pedido
No exemplo acima, observe a função getHeader() que retorna um determinado cabeçalho da solicitação. A classe 4D.IncomingMessage também oferece uma propriedade headers (Object) que contém todos os cabeçalhos do pedido.
O cabeçalho Content-Type fornece o formato do corpo recebido. Neste exemplo, apenas os formatos pdf e jpeg são tratados.
Note as funções getBlob() e getPicture() no objeto $request. Elas fornecem o conteúdo do corpo no formato apropriado que corresponde ao cabeçalho Content-Type.
Consulte a documentação para obter mais detalhes sobre essas funções.
Uma função getText() também está disponível e fornece o corpo do pedido como uma String (se tiver sido enviado como uma String)
Se o corpo tiver sido fornecido como uma representação JSON válida, a função getJSON() fornece a sua resolução com o tipo correto (por exemplo, Object, Collection, String, …).
manipular o redirecionamento
O manipulador de pedidos também é capaz de redirecionar para uma página específica devolvendo uma instância da classe4D.OutgoingMessage . O cabeçalho Location tem de ser utilizado para indicar a página para onde redirecionar.
O valor de status HTTP 3xx indica que o cliente deve realizar uma ação adicional para concluir a solicitação.
Vamos executar este cenário:
– O usuário pode ver todas as páginas html na pasta WebFolder/pages assim que estiver autenticado. Enquanto o usuário não for autenticado, será redirecionado para uma página de autenticação.
– Se a página pedida não estiver nesta pasta, é apresentada uma página Não encontrada.
– Se o utilizador pedir uma página numa subpasta da pasta /pages, é apresentada uma página Não autorizado.
O arquivo HTTPHandlers.json:
[
{
"class": "PagesHandling",
"method": "handle",
"regexPattern": "/pages/"
}
]
A classe singleton PagesHandling:
shared singleton Class constructor()
Function handle($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $file : 4D.File
//O usuário não é autenticado
If (Session.isGuest())
$result.setHeader("Location"; "/authentication/Authentication.html")
$result.setStatus(307)
Else
//A URL é uma página html na pasta /pages
If (($request.urlPath.length=2) && (Position(".html"; $request.url)#0))
$file:=File("/PACKAGE/WebFolder"+$request.url)
// pages existe
If ($file.exists)
$result.setBody($file.getContent())
$result.setHeader("Content-Type"; "text/html")
$result.setStatus(200)
//pages não existe
Else
$result.setHeader("Location"; "/error/NotFound.html")
$result.setStatus(307)
End if
//A URL NÃO é uma página html na pasta /pages
Else
$result.setHeader("Location"; "/error/NotAuthorized.html")
$result.setStatus(307)
End if
End if
return $result
Observe que o manipulador de solicitação tem acesso ao objeto Session, que permite uma lógica de negócios mais complexa (verificar a presença de alguns privilégios, usar o objeto compartilhado Session.storage ).
Descarregue o HDI para praticar o tratamento dos pedidos HTTP e não espere mais para entrar no mundo do modo de projeto que propõe classes e outras funcionalidades poderosas.