Durante la última década, han aparecido una gran cantidad de marcos web Rust, cada uno de ellos creado teniendo en cuenta usuarios y necesidades de funciones ligeramente diferentes. Todos ellos se benefician de la seguridad de tipos, seguridad de memoria, velocidad y corrección de Rust. Este artículo es un vistazo rápido a cinco de los marcos web de Rust más populares: Actix Web, Rocket, Warp, Axum y Poem. Todos ellos proporcionan elementos comunes para los servicios web: enrutamiento, manejo de solicitudes, múltiples tipos de respuesta y middleware. Tenga en cuenta que estos marcos no proporcionan plantillas, que normalmente se manejan mediante cajas separadas. Actix Web Actix Web es fácilmente el marco web más popular para Rust. Satisface casi todas las necesidades principales: es de alto rendimiento, admite una amplia gama de funciones de servidor y requiere poca ceremonia para crear un sitio básico. El nombre «Actix Web» originalmente se refería a la dependencia del marco del marco del actor actix. , pero el marco eliminó esa dependencia hace algún tiempo. Todas las funciones de Actix Web están disponibles en la rama estable de Rust. Aquí hay una aplicación básica de «hola mundo» en Actix Web: use actix_web::{get, App, HttpResponse, HttpServer, Responder}; #[get(«https://www.infoworld.com/»)]
async fn hola() -> impl Responder { HttpResponse::Ok().body(«¡Hola mundo!») } #[actix_web::main]
asíncrono fn main() -> std::io::Resultado<()> { HttpServer::nuevo(|| Aplicación::nuevo().servicio(hola)) .bind((«127.0.0.1», 8080))? .run() .await } El atributo get() en la función hello() indica qué ruta debe dar servicio, pero no está activo hasta que se agrega al objeto App con el método .service(). Actix Web también admite una construcción de rutas más avanzada; por ejemplo, puede capturar variables posicionales de la URL y usarlas para enrutar solicitudes a funciones que no usan get(). El rendimiento es un gran atractivo para Actix Web. Todas las solicitudes y respuestas se manejan como tipos distintos. El servidor utiliza un grupo de subprocesos para manejar las solicitudes, sin compartir nada entre los subprocesos para maximizar el rendimiento. Puede compartir el estado manualmente si es necesario, utilizando un Arc<>, pero los mantenedores de Actix Web recomiendan no hacer nada que bloquee los subprocesos de trabajo y, por lo tanto, sabotee el rendimiento. Para trabajos de larga duración sin CPU, utilice futuros o async. Actix Web también proporciona controladores basados ​​en tipos para códigos de error y utiliza un sistema de middleware integrado (que también puede utilizar) para implementar el registro. El marco también incluye un sistema de gestión de sesiones de usuario de uso general con cookies como tipo de almacenamiento predeterminado, aunque puede agregar otras si lo desea. Los archivos y directorios estáticos también se pueden servir con sus propios controladores dedicados. Muchas funciones comunes de servicios web vienen incluidas con Actix Web, junto con algunas que son menos comunes. Estos incluyen el manejo de cuerpos codificados en URL para formularios, la promoción automática a HTTPS/2, la descompresión de datos comprimidos con Brotli, gzip, deflate y zstd, y el manejo de codificación fragmentada. Para WebSockets, Actix Web requiere la caja actix-web-actors, que es su principal dependencia. Del mismo modo, para transmisiones multiparte, necesita la caja actix-multipart. (Para convertir hacia y desde JSON, Actix Web usa serde y serde_json, que deberían ser familiares para los usuarios de Rust en general). Actix Web llamó la atención en 2020 cuando su responsable original abandonó el proyecto, supuestamente por críticas sobre el uso de código inseguro. . Sin embargo, otros mantenedores líderes continuaron desarrollando el marco, y éste ha seguido creciendo en los años posteriores. Se ha eliminado gran parte del código inseguro. La gran distinción de RocketRocket entre los marcos web de Rust es que le permite obtener la mayor cantidad de resultados con la menor cantidad de código. Escribir una aplicación web básica en Rocket requiere relativamente pocas líneas y poca ceremonia. Rocket logra esto utilizando el sistema de tipos de Rust para describir muchos comportamientos, de modo que puedan aplicarse y codificarse en el momento de la compilación. Aquí hay una aplicación básica de «hola mundo» en Rocket: #[macro_use] cohete de caja externo; #[get(«https://www.infoworld.com/»)]
fn hello_world() -> &’static str { «¡Hola mundo!» } #[launch]
fn rocket() -> _ { rocket::build().mount(«https://www.infoworld.com/», rutas![hello_world]) } Rocket funciona de manera concisa mediante el uso de atributos. Las rutas están decoradas con atributos para los métodos y patrones de URL que utilizan. Como puede ver en este ejemplo, el #[launch] El atributo indica la función utilizada para montar las rutas y configurar la aplicación para escuchar solicitudes. Aunque las rutas en el ejemplo «hola mundo» son síncronas, las rutas pueden ser asíncronas en Rocket y, en general, deberían serlo cuando sea posible. De forma predeterminada, Rocket utiliza el tiempo de ejecución de Tokio para manejar cosas como convertir operaciones de sincronización a asíncronas. Rocket proporciona muchas de las funciones habituales para manejar solicitudes, por ejemplo, extraer variables de elementos URL. Una característica única son los «protectores de solicitudes», donde se utilizan tipos de Rust, implementando el rasgo FromRequest de Rocket, para describir una política de validación para una ruta. Por ejemplo, puede crear un tipo personalizado para evitar que una ruta se active a menos que cierta información esté presente en los encabezados de solicitud y podrían validarse, como una cookie con un determinado permiso asociado. Esto le permite crear cosas como permisos en la seguridad de tipos en tiempo de compilación de Rust. Otra característica útil y distintiva de Rocket son los carenados, la versión de middleware de Rocket. Los tipos que implementan el rasgo Fairing se pueden usar para agregar devoluciones de llamada a eventos, como solicitudes o respuestas. Pero los carenados no pueden cambiar ni detener las solicitudes (aunque pueden acceder a copias de los datos de la solicitud). Con ese fin, los carenados son mejores para cosas que tienen un comportamiento global: registros, recopilación de métricas de rendimiento o políticas de seguridad generales. Para acciones como la autenticación, utilice una protección de solicitudes. La gran distinción de WarpWarp de otros marcos web de Rust es la forma en que utiliza componentes componibles («filtros», en la jerga de Warp) que se pueden encadenar para crear servicios. Un «hola mundo» básico en Warp no demuestra esta característica particularmente bien, pero vale la pena mostrar cuán conciso puede ser el marco: use warp::Filter; #[tokio::main]
async fn main() { let hola = warp::path!().map(|| «Hola mundo»); warp::serve(hola).run(([127, 0, 0, 1]8080)).esperar; } Los filtros implementan el rasgo de filtro, cada filtro es capaz de pasar resultados a otro filtro para modificar comportamientos. En este ejemplo, warp::path es un archivador que se puede encadenar a otras operaciones, como .map() para aplicar una función. Otro ejemplo de la documentación de Warp muestra el sistema de filtrado con más detalle: use warp::Filter; let hi = warp::path(«hola») .and(warp::path::param()) .and(warp::header(«user-agent»)) .map(|param: String, agente: Cadena| {formato!(«Hola {}, cuyo agente es {}», parámetro, agente) }); Aquí, se encadenan varios filtros para crear el siguiente comportamiento, en este orden: Configure un punto final con la ruta hola. Agregue un parámetro al final de la ruta, por lo que la ruta debe tener el formato /hola/. (El método .and() es una de las formas en que funciona la composición en Warp). Agregue un analizador para el encabezado del agente de usuario, de modo que cualquier solicitud entrante sin encabezado de agente de usuario no se procese. ¡Aplica el formato! macro con los parámetros param (el parámetro recopilado) y agent (la cadena usuario-agente) en una cadena y devolverla al cliente. A los desarrolladores aficionados al enfoque compositivo les gustará cómo Warp complementa su forma de trabajar. Una consecuencia del enfoque compositivo es que puedes hacer lo mismo de diferentes maneras, no todas intuitivas. Vale la pena mirar los ejemplos en el repositorio de Warp para ver las diferentes formas de resolver escenarios de programación comunes usando Warp. Otra consecuencia proviene de la forma en que funcionan los filtros en tiempo de compilación. Componer muchas rutas a partir de muchos filtros diferentes puede prolongar el tiempo de compilación, aunque las rutas son rápidas en tiempo de ejecución. Otra opción es utilizar el envío dinámico para sitios con muchas rutas, con un ligero costo para el rendimiento del tiempo de ejecución. Un ejemplo muestra cómo hacer esto con un tipo BoxedFilter. Axum El marco Axum se construye sobre el ecosistema de cajas de torre para aplicaciones cliente/servidor de todo tipo, así como también tokio para asíncrono. Esto hace que sea más fácil usar Axum si ya tiene experiencia con Tower o la usa en proyectos aliados. Aquí hay una aplicación básica de «hola mundo» de Axum que se encuentra en la documentación de Axum. Notarás que no se ve tan diferente de Actix: use axum::{ route::get, Router, }; #[tokio::main]
async fn main() { let app = Router::new().route(«https://www.infoworld.com/», get(|| async { «¡Hola mundo!» })); let oyente = tokio::net::TcpListener::bind(«127.0.0.1:8080»).await.unwrap(); axum::serve(oyente, aplicación).await.unwrap(); } Axum utiliza muchos de los mismos patrones que Actix sobre cómo funcionan las rutas y los controladores. Las funciones de controlador de ruta se agregan a un objeto Router con el método .route(), y el módulo axum::extract contiene tipos para extraer componentes de URL o cargas útiles POST. Las respuestas implementan el rasgo IntoResponse y los errores se manejan a través del propio tipo de error tower::Service de la torre. Este último comportamiento, que depende de la torre para los componentes clave de Axum, también incluye cómo Axum maneja el middleware. A los enrutadores, métodos y controladores individuales se les puede aplicar middleware mediante diferentes métodos .layer en objetos de torre. También se puede utilizar tower::ServiceBuilder para crear agregados de múltiples capas y aplicarlas juntas. Axum proporciona sus propias herramientas para otros patrones comunes en los servicios web. Compartir el estado entre controladores, por ejemplo, se puede hacer de forma segura con un tipo State. En el directorio de ejemplos de Axum se pueden encontrar formas de implementar escenarios típicos, como cierres ordenados o configuración de conectividad de bases de datos. Poem La mayoría de los lenguajes tienen al menos un marco web «maximalista» con todas las funciones (por ejemplo, Django en Python) y uno pequeño, conciso y Marco web «minimalista» (por ejemplo, Bottle, nuevamente en Python). Poem se encuentra en el extremo mínimo del espectro de Rust y ofrece funciones suficientes de forma predeterminada para mantener un servicio web básico. Aquí hay un ejemplo de «hola mundo» que hace eco del nombre de usuario cuando se incluye en la URL: use poema::{get, handler , oyente::TcpListener, web::Ruta, Ruta, Servidor}; #[handler]
fn hola(Ruta(nombre): Ruta) -> Cadena {formato!(«hola: {}», nombre) } #[tokio::main]
asíncrono fn main() -> Resultado<(), std::io::Error> { let app = Ruta::new().at(«/hola/:nombre», get(hola)); Server::new(TcpListener::bind(«0.0.0.0:3000»)) .run(app) .await } Muchas de las características de esta aplicación deberían resultar familiares de los otros marcos y ejemplos que ha visto hasta ahora: configurar rutas, vincular URL y controladores a ellas, extraer elementos de la solicitud, etc. Para mantener el tiempo de compilación bajo, Poem de forma predeterminada no instala soporte para ciertas características. Las cookies, la proyección CSRF, HTTP sobre TLS, WebSockets, la internacionalización y la compresión y descompresión de solicitud/respuesta (por nombrar algunos) deben habilitarse manualmente. A pesar de su simplicidad, Poem aún ofrece muchas utilidades. Incluye una gran cantidad de piezas de middleware útiles y comunes, y también puedes implementar las tuyas propias con bastante facilidad. Una conveniencia interesante es NormalizePath, un mecanismo para hacer que las rutas de solicitud sean consistentes. Esto incluye un controlador universal para manejar barras diagonales en una URL. Con el controlador, puede implementar su formato preferido una vez y de manera consistente en toda la aplicación. El directorio de ejemplos de Poem es más pequeño que algunos de los otros marcos que ha visto aquí, pero se centra principalmente en ejemplos que requieren documentación detallada, como el uso de Poem con AWS Lambda o generar API que se ajusten a la especificación OpenAPI. ¿Qué marco Rust es mejor para usted? Actix Web funciona como una solución buena y equilibrada en general, especialmente si el objetivo es el rendimiento. Rocket le permite mantener su código breve pero expresivo, y su sistema de «carenados» proporciona una metáfora poderosa para implementar el comportamiento del middleware. Los programadores a quienes les gusta trabajar con elementos componibles querrán probar Warp, ya que les permite crear rutas y flujos de trabajo mediante programación con excelentes expresividad. Axum atraerá más directamente a los usuarios de Rust que ya están familiarizados con el ecosistema de la torre, pero es lo suficientemente útil como para que tampoco se limite a esa audiencia. Poem es simple por defecto, y es excelente en ese sentido si todo lo que necesita es el enrutamiento y el manejo de solicitudes más básicos. También puede instalar funciones adicionales si las necesita. Copyright © 2024 IDG Communications, Inc.