Interfaz para servidores web, marcos y clientes HTTP.
Consulte RAXX.KIT para un generador de proyectos que lo ayude a configurar un proyecto web basado en 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 / tiene ruta [] . Para iniciar un servidor RAXX, se necesita un servidor HTTP compatible. Este ejemplo usa ACE que puede servir tanto HTTP/1 como 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 . En este ejemplo no se usa y, por lo tanto, se establece en nulo.Comience su proyecto y visite http: // localhost: 8080.
Un intercambio HTTP implica un cliente que envía datos a un servidor que recibe una respuesta. Una vista simple es modelar esto como un solo mensaje enviado en cada dirección. Trabajar con este modelo corresponde a las devoluciones de llamada Raxx.SimpleServer .
request -->
Client ============================================ Server
<-- response Cuando el modelo simple es insuficiente, RAXX expone un modelo inferior. Esto consiste en una serie de mensajes en cada dirección. Trabajar con este modelo corresponde a las devoluciones de llamada Raxx.Server .
tail | data(1+) | head(request) -->
Client ============================================ Server
<-- head(response) | data(1+) | tail El servidor LongPoll es con el estado. Después de recibir una solicitud completa, este servidor debe esperar una entrada adicional antes de enviar una respuesta al 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[] ; y el nuevo estado del servidor, en este caso no hay state de cambio.initial_state está configurado cuando se inicia el servidor. El servidor SubscribeToMessages transmite su respuesta. El servidor enviará el jefe de la respuesta al recibir la solicitud. Los datos se envían al cliente, como parte del cuerpo, cuando está disponible. La respuesta se completa cuando la sala de chat envía un :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 la respuesta tiene un cuerpo que aún no se conoce. El servidor Upload escribe datos en un archivo tal como se recibe. Solo una vez que se ha recibido la solicitud completa, se envía una respuesta.
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 se invocará a medida que llegue cada parte. Una aplicación nunca debe asumir cómo un cuerpo se dividirá en piezas de datos. Vale la pena señalar qué garantías se dan en las piezas de solicitud pasadas a las funciones handle_* del servidor. Depende del tipo de servidor, Raxx.Server vs Raxx.SimpleServer :
Entonces, por ejemplo, después de un %Raxx.Request{body: false} se pasa a la devolución de llamada c:Raxx.Server.handle_head/2 de un servidor al servidor ( c:Raxx.Server.handle_info/2 Los mensajes podrían ser).
Del mismo modo, estas son las secuencias válidas de las partes de respuesta devueltas de los servidores:
Cualquier Raxx.Middleware s debe seguir la misma lógica.
El Raxx.Router se puede usar para hacer coincidir las solicitudes con 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