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