Интерфейс для HTTP Webservers, Frameworks и клиентов.
См. Raxx.kit для генератора проекта, который поможет вам настроить веб -проект на основе 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 / имеет путь [] . Чтобы запустить сервер RAXX, необходим совместимый HTTP -сервер. В этом примере используется ACE, который может служить как HTTP/1, так и 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 . В этом примере это неиспользовано и поэтому установлено в ноль.Начните свой проект и посетите http: // localhost: 8080.
HTTP Exchange включает в себя клиент, отправляющий данные на сервер, получающий ответ. Простой вид состоит в том, чтобы моделировать это как одно сообщение, отправленное в каждом направлении. Работа с этой моделью соответствует обратным вызовам Raxx.SimpleServer .
request -->
Client ============================================ Server
<-- response Когда простая модель недостаточно, Raxx выявляет более низкую модель. Это состоит из ряда сообщений в каждом направлении. Работа с этой моделью соответствует обратным вызовам Raxx.Server .
tail | data(1+) | head(request) -->
Client ============================================ Server
<-- head(response) | data(1+) | tail Сервер LongPoll является состоянием. После получения полного запроса этот сервер должен ждать дополнительный ввод перед отправкой ответа клиенту.
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[] ; и новое состояние сервера, в данном случае без state изменений.initial_state настроен при запуске сервера. Сервер SubscribeToMessages потокового ответа. Сервер отправит главу ответа при получении запроса. Данные отправляются клиенту, как часть тела, когда он становится доступным. Ответ завершается, когда в чате отправляется :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) отмечает, что в ответ есть тело, которое он еще не известен. Сервер Upload записывает данные в файл по мере его получения. Только после получения полного запроса отправлен ответ.
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 будет вызвана по мере появления каждой части. Приложение никогда не должно предполагать, как тело будет разбито на детали данных. Стоит отметить, какие гарантии предоставляются на деталях запроса, передаваемых функциям сервера handle_* . Это зависит от типа сервера, Raxx.Server vs Raxx.SimpleServer :
Так, например, после того, как %Raxx.Request{body: false} передается на обратный вызов сервера c:Raxx.Server.handle_head/2 , дальнейшие детали запроса не будут переданы на сервер ( c:Raxx.Server.handle_info/2 , однако, сообщения).
Точно так же это действительные последовательности частей ответа, возвращаемых с серверов:
Любой Raxx.Middleware S должен следовать той же логике.
Raxx.Router может использоваться для сопоставления запросов с определенными серверными модулями.
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