欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Rust Web框架Tide使用

程序员文章站 2022-05-07 19:13:38
目录简介快速开始发送和接收数据json数据静态文件重定向简介rust官方推出的基于async-std的异步web框架,目前最新版本为v0.11.0,还不太成熟。快速开始创建项目cargo new tide-demo在cargo.toml中添加依赖[dependencies]tide = "0.11.0"async-std = { version = "1.6.0", features = ["attributes"]修改main.js#[async_std::main]...

简介

rust官方推出的基于async-std的异步web框架,内部使用了http服务端和客户端抽象库http_types,目前最新版本为v0.11.0,目前还不太成熟,比如缺少文档、缺少stream流式编程风格(master版本已经支持此特性)、缺少像rocket或actix-web那样的路由宏定义(如#[get("/hello")]).

快速开始

  1. 创建项目
cargo new tide-demo
  1. 在cargo.toml中添加依赖
[dependencies]
tide = "0.11.0"
async-std = { version = "1.6.0", features = ["attributes"]
  1. 修改main.js
#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    let mut app = tide::new();
    app.at("/").get(|_| async { Ok("Hello, world!") });
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}
  1. 启动
cargo run
  1. 访问
    打开浏览器访问http://localhost:8080/

Request和Response

body json数据

content-type=application/json

use async_std::task;
use serde::{Deserialize, Serialize};
use tide::prelude::*;
use tide::{Body, Request, Response};

#[derive(Deserialize, Serialize)]
struct Cat {
    name: String,
}

fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();

        app.at("/submit").post(|mut req: Request<()>| async move {
            let cat: Cat = req.body_json().await?;
            println!("cat name: {}", cat.name);

            let cat = Cat {
                name: "chashu".into(),
            };

            let mut res = Response::new(200);
            res.set_body(Body::from_json(&cat)?);
            Ok(res)
        });

        app.at("/animals").get(|_| async {
            Ok(json!({
                "meta": { "count": 2 },
                "animals": [
                    { "type": "cat", "name": "chashu" },
                    { "type": "cat", "name": "nori" }
                ]
            }))
        });

        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

body string数据

content-type=text/plain;charset=utf-8

use async_std::task;
use tide::{ Request};

fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();
        app.at("/").post(|mut req: Request<()>| async move {
            let body: String = req.body_string().await.unwrap();
            println!("body: {}", body);
            Ok("")
        });

        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

从path中获取参数

use async_std::task;
use tide::prelude::*;
use tide::{Body, Request, Response};

fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();

        app.at("/:name").get(|mut req: Request<()>| async move {
            let name = req.param("name").unwrap();
            println!(" name: {}", name);

            let mut res = Response::new(200);
            res.set_body(Body::from_string(name));
            Ok(res)
        });

        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

从query中获取参数

use async_std::task;
use tide::prelude::*;
use tide::{Body, Request, Response};
#[derive(Serialize,Deserialize)]
struct Test {
    name: String,
    age: u32,
}
fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();
        app.at("/").get(|mut req: Request<()>| async move {
            let test:Test= req.query().unwrap();
            println!(" name: {}", test.name);
            println!(" age: {}", test.age);
            let mut res = Response::new(200);
            res.set_body(Body::from_json(&test)?);
            Ok(res)
        });

        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

从form中获取参数

content-type=application/x-www-form-urlencoded

use async_std::task;
use tide::prelude::*;
use tide::{Body, Request, Response};
#[derive(Serialize,Deserialize)]
struct Test {
    name: String,
    age: u32,
}
fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();
        app.at("/").get(|mut req: Request<()>| async move {
            let test:Test= req.query().unwrap();
            println!(" name: {}", test.name);
            println!(" age: {}", test.age);
            let mut res = Response::new(200);
            res.set_body(Body::from_json(&test)?);
            Ok(res)
        });

        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

状态码设置

use async_std::task;
use tide::{StatusCode, Request,Response};

fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();
        app.at("/").get(|mut req: Request<()>| async move {
            let mut res = Response::new(StatusCode::Ok);
            //let mut res = Response::new(200);
            res.set_body("Hello, Nori!");
            Ok(res)
        });
        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

返回内容type设置

use async_std::task;
use tide::{StatusCode, Request,Response};
use http_types::Mime;
use std::str::FromStr;

fn main() -> tide::Result<()> {
    task::block_on(async {
        let mut app = tide::new();
        app.at("/").get(|mut req: Request<()>| async move {
            let mut res = Response::new(StatusCode::Ok);
            let mime = Mime::from_str("text/html;charset=utf-8").unwrap();
            res.set_content_type(mime);
            res.set_body("<h1>Hello, Nori!</h1>");
            Ok(res)
        });
        app.listen("127.0.0.1:8080").await?;
        Ok(())
    })
}

日志

use tide::log;

log::start();

log::info!("Hello cats");
log::debug!("{} wants tuna", "Nori");
log::error!("We're out of tuna!");
log::info!("{} are hungry", "cats", {
    cat_1: "Chashu",
    cat_2: "Nori",
});

静态文件

#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    tide::log::start();
    let mut app = tide::new();
    app.at("/").get(|_| async move { Ok("visit /src/*") });
    app.at("/src").serve_dir("src/")?;
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}

重定向

use tide::{http::StatusCode, Redirect, Response};

#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    let mut app = tide::new();
    app.at("/").get(|_| async { Ok("Root") });

    // Redirect hackers to YouTube.
    app.at("/.env")
        .get(Redirect::new("https://www.youtube.com/watch?v=dQw4w9WgXcQ"));

    app.at("/users-page").get(|_| async {
        Ok(if signed_in() {
            Response::new(StatusCode::Ok)
        } else {
            // If the user is not signed in then lets redirect them to home page.
            Redirect::new("/").into()
        })
    });

    app.listen("127.0.0.1:8080").await?;
    Ok(())
}

fn signed_in() -> bool {
    false
}

middleware中间件

和nodejs里的koa 中间件类似

use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tide::http::mime;
use tide::{After, Before, Middleware, Next, Request, Response, Result, StatusCode};

#[derive(Debug)]
struct User {
    name: String,
}

#[derive(Default, Debug)]
struct UserDatabase;
impl UserDatabase {
    async fn find_user(&self) -> Option<User> {
        Some(User {
            name: "nori".into(),
        })
    }
}

// This is an example of a function middleware that uses the
// application state. Because it depends on a specific request state,
// it would likely be closely tied to a specific application
fn user_loader<'a>(
    mut request: Request<UserDatabase>,
    next: Next<'a, UserDatabase>,
) -> Pin<Box<dyn Future<Output = Result> + Send + 'a>> {
    Box::pin(async {
        if let Some(user) = request.state().find_user().await {
            tide::log::trace!("user loaded", {user: user.name});
            request.set_ext(user);
            next.run(request).await
        // this middleware only needs to run before the endpoint, so
        // it just passes through the result of Next
        } else {
            // do not run endpoints, we could not find a user
            Ok(Response::new(StatusCode::Unauthorized))
        }
    })
}

//
//
// this is an example of middleware that keeps its own state and could
// be provided as a third party crate
#[derive(Default)]
struct RequestCounterMiddleware {
    requests_counted: Arc<AtomicUsize>,
}

impl RequestCounterMiddleware {
    fn new(start: usize) -> Self {
        Self {
            requests_counted: Arc::new(AtomicUsize::new(start)),
        }
    }
}

struct RequestCount(usize);

impl<State: Send + Sync + 'static> Middleware<State> for RequestCounterMiddleware {
    fn handle<'a>(
        &'a self,
        mut req: Request<State>,
        next: Next<'a, State>,
    ) -> Pin<Box<dyn Future<Output = Result> + Send + 'a>> {
        Box::pin(async move {
            let count = self.requests_counted.fetch_add(1, Ordering::Relaxed);
            tide::log::trace!("request counter", { count: count });
            req.set_ext(RequestCount(count));

            let mut res = next.run(req).await?;

            res.insert_header("request-number", count.to_string());
            Ok(res)
        })
    }
}

const NOT_FOUND_HTML_PAGE: &str = "<html><body>
  <h1>uh oh, we couldn't find that document</h1>
  <p>
    probably, this would be served from the file system or
    included with `include_bytes!`
  </p>
</body></html>";

const INTERNAL_SERVER_ERROR_HTML_PAGE: &str = "<html><body>
  <h1>whoops! it's not you, it's us</h1>
  <p>
    we're very sorry, but something seems to have gone wrong on our end
  </p>
</body></html>";

#[async_std::main]
async fn main() -> Result<()> {
    tide::log::start();
    let mut app = tide::with_state(UserDatabase::default());

    app.middleware(After(|result: Result| async move {
        let response = result.unwrap_or_else(|e| Response::new(e.status()));
        match response.status() {
            StatusCode::NotFound => {
                let mut res = Response::new(404);
                res.set_content_type(mime::HTML);
                res.set_body(NOT_FOUND_HTML_PAGE);
                Ok(res)
            }
            StatusCode::InternalServerError => {
                let mut res = Response::new(500);
                res.set_content_type(mime::HTML);
                res.set_body(INTERNAL_SERVER_ERROR_HTML_PAGE);
                Ok(res)
            }
            _ => Ok(response),
        }
    }));

    app.middleware(user_loader);
    app.middleware(RequestCounterMiddleware::new(0));
    app.middleware(Before(|mut request: Request<UserDatabase>| async move {
        request.set_ext(std::time::Instant::now());
        request
    }));

    app.at("/").get(|req: Request<_>| async move {
        let count: &RequestCount = req.ext().unwrap();
        let user: &User = req.ext().unwrap();

        Ok(format!(
            "Hello {}, this was request number {}!",
            user.name, count.0
        ))
    });

    app.listen("127.0.0.1:8080").await?;
    Ok(())
}

本文地址:https://blog.csdn.net/kk3909/article/details/107202731