Pedidos HTTP mestre com 4D Request Handlers

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.

HDI_HTTP_RequestHandler

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.

Avatar
• Proprietário do produto - Marie-Sophie Landrieu -Yvert entrou ao time 4D Product como Proprietária do Produto em 2017. Como tal, está a cargo de escrever as histórias dos usuários e depois traduzi-las em especificações funcionais. Seu papel também é garantir que a implementação da funcionalidade entregue cumpra com as necessidades do cliente. Marie-sophie se formou na Escola de Engenharia de ESIGELEC e começou sua carreira como engenheira da IBM em 1995. Participou em vários projetos (de manutenção e criação) e trabalhou como desenvolvedora de Cobol. Depois trabalhou como designer de UML e desenvolvedora de Java. Suas principais funções foram analisar e redigir requisitos funcionais, coordenar os times de negócio e de desenvolvimento.