Interface para servidores da web HTTP, estruturas e clientes.
Consulte Raxx.kit para um gerador de projetos que o ajuda a configurar um projeto da Web com base no RAXX/ACE.
defmodule MyServer do
use Raxx.SimpleServer
@ impl Raxx.SimpleServer
def handle_request ( % { method: :GET , path: [ ] } , _state ) do
response ( :ok )
|> set_header ( "content-type" , "text/plain" )
|> set_body ( "Hello, World!" )
end
def handle_request ( % { method: :GET , path: _ } , _state ) do
response ( :not_found )
|> set_header ( "content-type" , "text/plain" )
|> set_body ( "Oops! Nothing here." )
end
endGET / tem caminho [] . Para iniciar um servidor RAXX, é necessário um servidor HTTP compatível. Este exemplo usa ACE que pode servir tanto HTTP/1 quanto HTTP/2.
raxx_server = { MyServer , nil }
http_options = [ port: 8080 , cleartext: true ]
{ :ok , pid } = Ace.HTTP.Service . start_link ( raxx_server , http_options )handle_request/2 . Neste exemplo, ele não está utilizado e, portanto, está pronto.Inicie seu projeto e visite http: // localhost: 8080.
Uma troca HTTP envolve um cliente enviando dados para um servidor que recebe uma resposta. Uma visão simples é modelar isso como uma única mensagem enviada em cada direção. Trabalhar com este modelo corresponde a Raxx.SimpleServer Retornos de chamada.
request -->
Client ============================================ Server
<-- response Quando o modelo simples é insuficiente, o RAXX expõe um modelo mais baixo. Isso consiste em uma série de mensagens em cada direção. Trabalhar com este modelo corresponde a retornos de chamada Raxx.Server .
tail | data(1+) | head(request) -->
Client ============================================ Server
<-- head(response) | data(1+) | tail O servidor LongPoll está com estado. Depois de receber uma solicitação completa, este servidor deve aguardar a entrada extra antes de enviar uma resposta ao cliente.
defmodule LongPoll do
use Raxx.Server
@ impl Raxx.Server
def handle_head ( % { method: :GET , path: [ "slow" ] } , state ) do
Process . send_after ( self ( ) , :reply , 30_000 )
{ [ ] , state }
end
@ impl Raxx.Server
def handle_info ( :reply , _state ) do
response ( :ok )
|> set_header ( "content-type" , "text/plain" )
|> set_body ( "Hello, Thanks for waiting." )
end
end[] ; e o novo estado do servidor, neste caso, nenhum state de mudança.initial_state é configurado quando o servidor é iniciado. O servidor SubscribeToMessages transmite sua resposta. O servidor enviará o chefe da resposta ao receber a solicitação. Os dados são enviados ao cliente, como parte do corpo, quando estão disponíveis. A resposta é concluída quando a sala de bate -papo envia a :closed .
defmodule SubscribeToMessages do
use Raxx.Server
@ impl Raxx.Server
def handle_head ( % { method: :GET , path: [ "messages" ] } , state ) do
{ :ok , _ } = ChatRoom . join ( )
outbound = response ( :ok )
|> set_header ( "content-type" , "text/plain" )
|> set_body ( true )
{ [ outbound ] , state }
end
@ impl Raxx.Server
def handle_info ( { ChatRoom , :closed } , state ) do
outbound = tail ( )
{ [ outbound ] , state }
end
def handle_info ( { ChatRoom , data } , state ) do
outbound = data ( data )
{ [ outbound ] , state }
end
endset_body(true) marca que a resposta tem um corpo que ainda não é conhecido. O servidor Upload grava dados em um arquivo conforme é recebido. Somente quando a solicitação completa for recebida é uma resposta enviada.
defmodule Upload do
use Raxx.Server
@ impl Raxx.Server
def handle_head ( % { method: :PUT , path: [ "upload" ] body: true } , _state ) do
{ :ok , io_device } = File . open ( "my/path" )
{ [ ] , { :file , device } }
end
@ impl Raxx.Server
def handle_data ( data , state = { :file , device } ) do
IO . write ( device , data )
{ [ ] , state }
end
@ impl Raxx.Server
def handle_tail ( _trailers , state ) do
response ( :see_other )
|> set_header ( "location" , "/" )
end
endhandle_data será invocado quando cada peça chegar. Um aplicativo nunca deve assumir como um corpo será dividido em peças de dados. Vale a pena notar quais garantias são fornecidas nas peças de solicitação passadas para as funções do handle_* do servidor. Depende do tipo de servidor, Raxx.Server vs Raxx.SimpleServer :
Assim, por exemplo, depois de um %Raxx.Request{body: false} é passado para o c:Raxx.Server.handle_head/2 de um retorno de chamada, nenhuma peça de solicitação adicional será passada para o servidor ( c:Raxx.Server.handle_info/2 Mensagens podem ser, porém).
Da mesma forma, essas são as seqüências válidas das peças de resposta retornadas dos servidores:
Qualquer Raxx.Middleware s deve seguir a mesma lógica.
O Raxx.Router pode ser usado para corresponder às solicitações a módulos de servidor específicos.
defmodule MyApp do
use Raxx.Server
use Raxx.Router , [
{ % { method: :GET , path: [ ] } , HomePage } ,
{ % { method: :GET , path: [ "slow" ] } , LongPoll } ,
{ % { method: :GET , path: [ "messages" ] } , SubscribeToMessages } ,
{ % { method: :PUT , path: [ "upload" ] } , Upload } ,
{ _ , NotFoundPage }
]
end