[Aprender Rust juntos | Framework | Viz framework] Framework web ligero - Viz


prefacio

A saber, es un marco web rápido, robusto, flexible y liviano basado en RUst.

características

  • seguro, prohibir código inseguro
  • Ligero
  • Procesador y middleware simples y flexibles
  • operación de cadena
  • Enrutamiento potente

1. Hola Viz

1. Crea un proyecto

Al igual que aprender un lenguaje de programación, comenzamos con el estudio de caso introductorio oficial, primero creamos un nuevo proyecto

cargo new viz_hello

Luego usa vscode para abrir

2. Introducir visualización

Escriba Cargo.toml, como se muestra a continuación

tokio = {
    
     version = "1.20.1", features = ["full"] }
viz = "0.3.1"

Luego use build para descargar dependencias

cargo build


La instalación se ha completado

3. Ejecute Hello Viz

Copie el siguiente código en main.rs,

use std::net::SocketAddr;
use viz::{
    
    Request, Result, Router, Server, ServiceMaker};

async fn index(_: Request) -> Result<&'static str> {
    
    
    Ok("Hello Viz")
}

#[tokio::main]
async fn main() -> Result<()> {
    
    
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("listening on {}", addr);

    let app = Router::new().get("/", index);

    if let Err(err) = Server::bind(&addr)
        .serve(ServiceMaker::from(app))
        .await
    {
    
    
        println!("{}", err);
    }

    Ok(())
}

4. Ejecución de resultados

Si no hay ningún problema con los pasos anteriores, ejecute en la terminal

cargo run

El efecto es como se
muestra en la siguiente figura, la última línea significa que está escuchando el puerto local 3000 de 127.0.0.1, lo que indica que el programa no tiene errores.

En este momento, abra la URL en el navegador

http://localhost:3000/

Aviso

localhost apunta a 127.0.0.1

La página ahora debería verse así

2. Explicación detallada del código Hello Viz


En general, este código se divide principalmente en tres partes, a saber, la importación de componentes, el procesamiento de solicitudes de índice y el programa principal.

componente de importación

En primer lugar, se importa SocketAddr para representar la dirección del socket y, a continuación, se importan algunos componentes de Viz.

  • Solicitud de solicitud
  • Respuesta de resultado
  • Enrutamiento de enrutador
  • servidor servidor
  • servicio ServiceMaker

solicitud de proceso

Aquí, se utiliza una función asíncrona para realizar el procesamiento del índice, y se pasa la Solicitud, y el sistema manejará automáticamente este proceso por nosotros. Luego, la respuesta es un tipo de cadena y la cadena "Hello Viz" se devuelve en el cuerpo de la función.

función principal

En Viz, la función principal también es una función asíncrona, use addr para indicar la dirección local y el puerto de escucha, luego monte el enrutador para conectarse con el procesador de índice y luego inicie el servidor.

3. Uso común

controlador sencillo

async fn index(_: Request) -> Result<Response> {
    
    
    Ok(Response::text("Hello, World!"))
}

async fn about(_: Request) -> Result<&'static str> {
    
    
    Ok("About Me!")
}

async fn not_found(_: Request) -> Result<impl IntoResponse> {
    
    
    Ok("Not Found!")
}

Implementando el rasgo de controlador

#[derive(Clone)]
struct MyHandler {
    
    
    code: Arc<AtomicUsize>,
}

#[async_trait]
impl Handler<Request> for MyHandler {
    
    
    type Output = Result<Response>;  

    async fn call(&self, req: Request) -> Self::Output {
    
    
        let path = req.path().clone();
        let method = req.method().clone();
        let code = self.code.fetch_add(1, Ordering::SeqCst);
        Ok(format!("code = {}, method = {}, path = {}", code, method, path).into_response())
    }
}

Parámetros de enrutamiento

Viz permite una organización más flexible del código.

async fn show_user(mut req: Request) -> Result<Response> {
    
    
    let Params(id)  = req.extract::<Params<u64>>().await?;
    Ok(format!("post {}", id).into_response())
}

async fn show_user_ext(Params(id): Params<u64>) -> Result<impl IntoResponse> {
    
    
    Ok(format!("Hi, NO.{}", id))
}

async fn show_user_wrap(req: Request) -> Result<impl IntoResponse> {
    
    
    // https://github.com/rust-lang/rust/issues/48919
    // show_user_ext.call(req).await
    FnExt::call(&show_user_ext, req).await
}

let app = Router::new()
    .get("/users/:id", show_user)
    .get("/users_wrap/:id", show_user_wrap)
    .get("/users_ext/:id", show_user_ext.into_handler());

programa de combinacion de cadenas

HandlerExt es una característica extendida de Handler, que proporciona varias funciones de combinación convenientes. Como los rasgos FutureExt y StreamExt.

async fn index(_: Request) -> Result<Response> {
    
    
    Ok(Response::text("hyper"))
}

async fn before(req: Request) -> Result<Request> {
    
    
    if req.method() == Method::POST {
    
    
        Ok(req)
    } else {
    
    
        Err(StatusCode::METHOD_NOT_ALLOWED.into_error())
    }
}

async fn around<H>((req, handler): Next<Request, H>) -> Result<Response>
where
    H: Handler<Request, Output = Result<Response>> + Clone,
{
    
    
    // before ...
    let result = handler.call(req).await;
    // after ...
    result
}

async fn after(result: Result<Response>) -> Result<Response> {
    
    
    result.map(|mut res| {
    
    
        *res.status_mut() = StatusCode::NO_CONTENT;
        res
    })
}

let routing = Router::new()
    .get("/", index.before(before).around(around).after(after));

software intermedio

El middleware y los controladores de Viz comparten un rasgo común de controlador, por lo que es fácil de implementar y ampliar el middleware.

Podemos agregar middleware a un solo controlador o a todos los controladores.

También podemos usar el rasgo Transformar durante la construcción para envolver controladores internos.

async fn index(_: Request) -> Result<Response> {
    
    
    Ok(StatusCode::OK.into_response())
}

async fn not_found(_: Request) -> Result<impl IntoResponse> {
    
    
    Ok(StatusCode::OK)
}

async fn show_user(Params(id): Params<u64>) -> Result<impl IntoResponse> {
    
    
    Ok(format!("post {}", id))
}

// middleware fn
async fn around<H>((req, handler): Next<Request, H>) -> Result<Response>
where
    H: Handler<Request, Output = Result<Response>>,
{
    
    
    // before ...
    let result = handler.call(req).await;
    // after ...
    result
}

// middleware struct
#[derive(Clone)]
struct MyMiddleware {
    
    }

#[async_trait]
impl<H> Handler<Next<Request, H>> for MyMiddleware
where
    H: Handler<Request>,
{
    
    
    type Output = H::Output;

    async fn call(&self, (i, h): Next<Request, H>) -> Self::Output {
    
    
        h.call(i).await
    }
}

// A configuration for Timeout Middleware
struct Timeout {
    
    
    delay: Duration,
}

impl Timeout {
    
    
    pub fn new(secs: u64) -> Self {
    
    
        Self {
    
     delay: Duration::from_secs(secs) }
    }
}

impl<H: Clone> Transform<H> for Timeout {
    
    
    type Output = TimeoutMiddleware<H>;

    fn transform(&self, h: H) -> Self::Output {
    
    
        TimeoutMiddleware(h, self.delay)
    }
}

// Timeout Middleware
#[derive(Clone)]
struct TimeoutMiddleware<H>(H, Duration);

#[async_trait]
impl<H> Handler<Request> for TimeoutMiddleware<H>
where
    H: Handler<Request> + Clone,
{
    
    
    type Output = H::Output;

    async fn call(&self, req: Request) -> Self::Output {
    
    
        self.0.call(req).await
    }
}

let app = Router::new()
    .get("/", index
        // handler level
        .around(around)
        .around(MyMiddleware {
    
    })
        .with(Timeout::new(1))
    )
    .route("/users/:id", get(
        show_user
            .into_handler()
            .map_into_response()
            // handler level
            .around(around)
            .with(Timeout::new(0))
        )
        .post(
            (|_| async {
    
     Ok(Response::text("update")) })
            // handler level
            .around(around)
            .with(Timeout::new(0))
        )
        // route level
        .with_handler(MyMiddleware {
    
    })
        .with(Timeout::new(2))
    )
    .get("/*", not_found
        .map_into_response()
        // handler level
        .around(around)
        .around(MyMiddleware {
    
    })
    )
    // router level
    .with_handler(around)
    .with_handler(MyMiddleware {
    
    })
    .with(Timeout::new(4));

receptor de parámetros

Extraer parámetros de Solicitud.

struct Counter(u16);

#[async_trait]
impl FromRequest for Counter {
    
    
    type Error = Infallible;
    async fn extract(req: &mut Request) -> Result<Self, Self::Error> {
    
    
        let c = get_query_param(req.query_string());
        Ok(Counter(c))
    }
}

fn get_query_param(query: Option<&str>) -> u16 {
    
    
   let query = query.unwrap_or("");
   let q = if let Some(pos) = query.find('q') {
    
    
       query.split_at(pos + 2).1.parse().unwrap_or(1)
   } else {
    
    
       1
   };
   cmp::min(500, cmp::max(1, q))
}

enrutamiento

Identifique URL y asigne controladores.

una ruta sencilla

async fn index(_: Request) -> Result<Response> {
    
    
    Ok(().into_response())
}

let root = Router::new()
  .get("/", index)
  .route("/about", get(|_| async {
    
     Ok("about") }));

let search = Router::new()
  .route("/", Route::new().get(|_| async {
    
     Ok("search") }));

Operaciones CRUD

Agregar método con método de solicitud.

async fn index_todos(_: Request) -> Result<impl IntoResponse> {
    
    
    Ok(())
}

async fn create_todo(_: Request) -> Result<&'static str> {
    
    
    Ok("created")
}

async fn new_todo(_: Request) -> Result<Response> {
    
    
    Ok(Response::html(r#"
        <form method="post" action="/">
            <input name="todo" />
            <button type="submit">Create</button>
        </form>
    "#))
}

async fn show_todo(mut req: Request) -> Result<Response> {
    
    
    let Params(id): Params<u64> = req.extract().await?;
    Ok(Response::text(format!("todo's id is {}", id)))
}

async fn update_todo(_: Request) -> Result<()> {
    
    
    Ok(())
}

async fn destroy_todo(_: Request) -> Result<()> {
    
    
    Ok(())
}

async fn edit_todo(_: Request) -> Result<()> {
    
    
    Ok(())
}

let todos = Router::new()
  .route("/", get(index_todos).post(create_todo))
  .post("/new", new_todo)
  .route("/:id", get(show_todo).patch(update_todo).delete(destroy_todo))
  .get("/:id/edit", edit_todo);

recurso

// GET `/search`
async fn search_users(_: Request) -> Result<Response> {
    
    
    Ok(Response::json::<Vec<u64>>(vec![])?)
}

// GET `/`
async fn index_users(_: Request) -> Result<Response> {
    
    
    Ok(Response::json::<Vec<u64>>(vec![])?)
}

// GET `/new`
async fn new_user(_: Request) -> Result<&'static str> {
    
    
    Ok("User Form")
}

// POST `/`
async fn create_user(_: Request) -> Result<&'static str> {
    
    
    Ok("Created User")
}

// GET `/user_id`
async fn show_user(_: Request) -> Result<&'static str> {
    
    
    Ok("User ID 007")
}

// GET `/user_id/edit`
async fn edit_user(_: Request) -> Result<&'static str> {
    
    
    Ok("Edit User Form")
}

// PUT `/user_id`
async fn update_user(_: Request) -> Result<&'static str> {
    
    
    Ok("Updated User")
}

// DELETE `/user_id`
async fn delete_user(_: Request) -> Result<&'static str> {
    
    
    Ok("Deleted User")
}

let users = Resources::default()
  .named("user")
  .route("/search", get(search_users))
  .index(index_users)
  .new(new_user)
  .create(create_user)
  .show(show_user)
  .edit(edit_user)
  .update(update_user)
  .destroy(delete_user);

Resumir

Este problema proporciona principalmente una comprensión básica del marco web ligero de Rust, Viz, y brinda el código de muestra oficial de Viz, incluido el uso de middleware, procesamiento de respuestas, enrutamiento y otros componentes. marco es muy simple. En los siguientes artículos, presentaremos la operación de la base de datos de rust, la operación json y otras tecnologías relacionadas, una tras otra. Rust completará las tecnologías relacionadas con el back-end web y comenzará el proyecto real. Si está interesado en el óxido, preste atención a esta serie de artículos.

Supongo que te gusta

Origin blog.csdn.net/weixin_47754149/article/details/126435523
Recomendado
Clasificación