Schnittstelle für HTTP -Webserver, Frameworks und Clients.
Siehe Raxx.kit für einen Projektgenerator, mit dem Sie ein Webprojekt basierend auf RAXX/ACE einrichten können.
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
end[] zu GET / hat. Um einen Raxx -Server zu starten, ist ein kompatibler HTTP -Server erforderlich. In diesem Beispiel wird ACE verwendet, das sowohl HTTP/1 als auch HTTP/2 dienen kann.
raxx_server = { MyServer , nil }
http_options = [ port: 8080 , cleartext: true ]
{ :ok , pid } = Ace.HTTP.Service . start_link ( raxx_server , http_options )handle_request/2 übergeben. In diesem Beispiel ist es nicht genutzt und so auf Null eingestellt.Starten Sie Ihr Projekt und besuchen Sie http: // localhost: 8080.
Ein HTTP -Exchange umfasst einen Client, der Daten an einen Server sendet, der eine Antwort empfängt. Eine einfache Ansicht besteht darin, dies als eine einzelne Nachricht zu modellieren, die in jede Richtung gesendet wurde. Die Arbeit mit diesem Modell entspricht Raxx.SimpleServer -Callbacks.
request -->
Client ============================================ Server
<-- response Wenn das einfache Modell nicht ausreicht, enthält Raxx ein niedrigeres Modell. Dies besteht aus einer Reihe von Nachrichten in jede Richtung. Die Arbeit mit diesem Modell entspricht Raxx.Server -Callbacks.
tail | data(1+) | head(request) -->
Client ============================================ Server
<-- head(response) | data(1+) | tail Der LongPoll -Server ist staatlich. Nach Erhalt einer vollständigen Anforderung muss dieser Server auf zusätzliche Eingaben warten, bevor eine Antwort an den Client gesendet wird.
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[] ; und der neue Status des Servers, in diesem Fall kein state .initial_state ist konfiguriert, wenn der Server gestartet wird. Der Server SubscribeToMessages streamt seine Antwort. Der Server sendet den Kopf der Antwort nach Erhalt der Anfrage. Daten werden als Teil des Körpers an den Client gesendet, wenn es verfügbar ist. Die Antwort ist abgeschlossen, wenn der Chatroom eine :closed Nachricht sendet.
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) markiert, dass die Antwort einen Körper hat, den sie noch nicht bekannt ist. Der Upload -Server schreibt Daten in eine Datei, wie sie empfangen wird. Erst wenn die vollständige Anfrage eingegangen ist, wird eine Antwort gesendet.
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 wird aufgerufen, wenn jedes Teil eintrifft. Eine Anwendung sollte niemals davon ausgehen, wie ein Körper in Datenteile unterteilt wird. Es ist erwähnenswert, welche Garantien auf den Anforderungsteilen angegeben sind, die an die handle_* des Servers übergeben werden. Es hängt vom Servertyp Raxx.Server gegen Raxx.SimpleServer ab:
So wird beispielsweise nach einem %Raxx.Request{body: false} an den c:Raxx.Server.handle_head/2 c:Raxx.Server.handle_info/2 Servers übergeben.
In ähnlicher Weise sind dies die gültigen Sequenzen der von den Servern zurückgegebenen Antwortteile:
Alle Raxx.Middleware S sollten derselben Logik folgen.
Der Raxx.Router kann verwendet werden, um die Anforderungen an bestimmte Servermodule abzustimmen.
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