¡Comience con ejemplos y tutoriales en nuestro sitio web!
¿No tienes tiempo para leer los documentos? Verificar
✅ se ejecuta en estable ✅ se ejecuta rápidamente ✅ no usa inseguro
Documentación
Thruster es un marco web que apunta a que los desarrolladores sean productivos y consistentes en todos los proyectos y equipos. Sus objetivos son:
Propulsores también
unsafeEl propulsor se puede ejecutar con diferentes backends del servidor y representa una capa bien empaquetada sobre ellos. Esto significa que puede mantenerse al día con los últimos y mayores cambios de los gustos de Hyper, Actix o incluso Thrusserver, un motor HTTP local.
Basado en marcos como KOA y Express, Thruster tiene como objetivo ser un placer desarrollar.
Para ejecutar el ejemplo cargo run --example <example-name> . Por ejemplo, cargo run --example hello_world y abre http: // localhost: 4321/
Las piezas centrales que hacen que el nuevo ASYNC espere el código que funcione es designar funciones de middleware con el atributo #[middleware_fn] (que marca el middleware para que sea compatible con la versión de futuros estable en la que se basa el thruster), y luego la m! Macro en las rutas reales.
Un ejemplo simple para usar async espera es:
use std :: boxed :: Box ;
use std :: future :: Future ;
use std :: pin :: Pin ;
use std :: time :: Instant ;
use thruster :: { App , BasicContext as Ctx , Request } ;
use thruster :: { m , middleware_fn , MiddlewareNext , MiddlewareResult , Server , ThrusterServer } ;
# [ middleware_fn ]
async fn profile ( context : Ctx , next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let start_time = Instant :: now ( ) ;
context = next ( context ) . await ;
let elapsed_time = start_time . elapsed ( ) ;
println ! (
"[{}μs] {} -- {}" ,
elapsed_time . as_micros ( ) ,
context . request . method ( ) ,
context . request . path ( )
) ;
Ok ( context )
}
# [ middleware_fn ]
async fn plaintext ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let val = "Hello, World!" ;
context . body ( val ) ;
Ok ( context )
}
# [ middleware_fn ]
async fn four_oh_four ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
context . status ( 404 ) ;
context . body ( "Whoops! That route doesn't exist!" ) ;
Ok ( context )
}
# [ tokio :: main ]
fn main ( ) {
println ! ( "Starting server..." ) ;
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
app . get ( "/plaintext" , m ! [ profile , plaintext ] ) ;
app . set404 ( m ! [ four_oh_four ] ) ;
let server = Server :: new ( app ) ;
server . build ( "0.0.0.0" , 4321 ) . await ;
}Aquí hay un buen ejemplo
use thruster :: errors :: ThrusterError as Error ;
use thruster :: proc :: { m , middleware_fn } ;
use thruster :: { map_try , App , BasicContext as Ctx , Request } ;
use thruster :: { MiddlewareNext , MiddlewareResult , MiddlewareReturnValue , Server , ThrusterServer } ;
# [ middleware_fn ]
async fn plaintext ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let val = "Hello, World!" ;
context . body ( val ) ;
Ok ( context )
}
# [ middleware_fn ]
async fn error ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let res = "Hello, world" . parse :: < u32 > ( )
. map_err ( |_| {
let mut context = Ctx :: default ( ) ;
context . status ( 400 ) ;
ThrusterError {
context ,
message : "Custom error message" . to_string ( ) ,
cause : None ,
}
} ? ;
context . body ( & format ! ( "{}" , non_existent_param ) ) ;
Ok ( context )
}
# [ tokio :: main ]
fn main ( ) {
println ! ( "Starting server..." ) ;
let app = App :: < Request , Ctx , ( ) > :: new_basic ( )
. get ( "/plaintext" , m ! [ plaintext ] )
. get ( "/error" , m ! [ error ] ) ;
let server = Server :: new ( app ) ;
server . build ( "0.0.0.0" , 4321 ) . await ;
} Thruster proporciona un conjunto de pruebas fácil para probar sus puntos finales, simplemente incluya el módulo testing como se muestra a continuación:
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
.. .
app . get ( "/plaintext" , m ! [ plaintext ] ) ;
.. .
let result = testing :: get ( app , "/plaintext" ) ;
assert ! ( result . body == "Hello, World!" ) ; ¡El middleware es súper fácil de hacer! Simplemente cree una función y expórela a nivel de módulo. A continuación, verá una pieza de middleware que permite el perfil de solicitudes:
# [ middleware_fn ]
async fn profiling < C : ' static + Context + Send > (
mut context : C ,
next : MiddlewareNext < C > ,
) -> MiddlewareResult < C > {
let start_time = Instant :: now ( ) ;
context = next ( context ) . await ? ;
let elapsed_time = start_time . elapsed ( ) ;
info ! ( "[{}μs] {}" , elapsed_time . as_micros ( ) , context . route ( ) ) ;
Ok ( context )
}Puede encontrar que desea permitir datos más específicos almacenados en el contexto, por ejemplo, tal vez desee poder hidratar los parámetros de consulta en un hashmap para su uso posterior por otros artículos intermedios. Para hacer esto, puede crear un rasgo adicional para el contexto al que debe adherirse a MiddleWares aguas abajo. Echa un vistazo al middleware de Query_Params proporcionado para obtener un ejemplo.
Thruster es capaz de proporcionar la capa de enrutamiento en la parte superior de un servidor de algún tipo, por ejemplo, en el hiper fragmento anterior. Esto se puede aplicar ampliamente a cualquier backend, siempre y cuando el servidor implementa ThrusterServer .
use async_trait :: async_trait ;
# [ async_trait ]
pub trait ThrusterServer {
type Context : Context + Send ;
type Response : Send ;
type Request : RequestWithParams + Send ;
fn new ( App < Self :: Request , Self :: Context > ) -> Self ;
async fn build ( self , host : & str , port : u16 ) ;
}Debe haber:
Dentro de la función build , la implementación del servidor debe:
let matched = app.resolve_from_method_and_path(<some method>, <some path>); (Esto proporciona el enrutamiento real).app.resolve(<incoming request>, matched) (esto ejecuta el middleware encadenado). fn ip_guard ( head : & RequestHead ) -> bool {
// Check for the cloudflare IP header
let ip = if let Some ( val ) = head . headers ( ) . get ( CF_IP_HEADER ) {
val . to_str ( ) . unwrap_or ( "" ) . to_owned ( )
} else if let Some ( val ) = head . peer_addr {
val . to_string ( )
} else {
return false ;
} ;
"1.2.3.4" . contains ( & ip )
}
# [ actix_web :: post ( "/ping" ) ]
async fn ping ( ) -> Result < HttpResponse , UserPersonalError > {
Ok ( HttpResponse :: Ok ( ) . body ( "pong" ) )
}
.. .
web :: scope ( "/*" )
// This is confusing, but we catch all routes that _aren't_
// ip guarded and return an error.
. guard ( guard :: Not ( ip_guard ) )
. route ( "/*" , web :: to ( HttpResponse :: Forbidden ) ) ,
)
. service ( ping ) ;
.. .Aquí está la fuga:
# [ middleware_fn ]
async fn ip_guard ( mut context : Ctx , next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
if "1.2.3.4" . contains ( & context . headers ( ) . get ( "Auth-Token" ) . unwrap_or ( "" ) ) {
context = next ( context ) . await ? ;
Ok ( context )
} else {
Err ( Error :: unauthorized_error ( context ) )
}
}
# [ middleware_fn ]
async fn ping ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
context . body ( "pong" ) ;
Ok ( context )
}
.. .
app . get ( "/ping" , m ! [ ip_guard , plaintext ] ) ;
.. .¡Un poco más directo es agradable!
Si llegaste tan lejos, ¡gracias por leer! Siempre siéntase libre de comunicarse.