<div align="center">
<p><img alt="Savlo" width="132" style="max-width:40%;min-width:60px;" src="https://salvo.rs/images/logo-text.svg" /></p>
<p>
<a href="https://github.com/salvo-rs/salvo/blob/main/README.md">English</a>
<a href="https://github.com/salvo-rs/salvo/blob/main/README.zh-hans.md">ç®ä½ä¸æ</a>
<a href="https://github.com/salvo-rs/salvo/blob/main/README.zh-hant.md">ç¹é«ä¸æ</a>
</p>
<p>
<a href="https://github.com/salvo-rs/salvo/actions">
<img alt="build status" src="https://github.com/salvo-rs/salvo/workflows/ci-linux/badge.svg?branch=main&event=push" />
</a>
<a href="https://github.com/salvo-rs/salvo/actions">
<img alt="build status" src="https://github.com/salvo-rs/salvo/workflows/ci-macos/badge.svg?branch=main&event=push" />
</a>
<a href="https://github.com/salvo-rs/salvo/actions">
<img alt="build status" src="https://github.com/salvo-rs/salvo/workflows/ci-windows/badge.svg?branch=main&event=push" />
</a>
<br>
<a href="https://discord.gg/G8KfmS6ByH">
<img src="https://img.shields.io/discord/1041442427006890014.svg?logo=discord">
</a>
<a href="https://crates.io/crates/salvo"><img alt="crates.io" src="https://img.shields.io/crates/v/salvo" /></a>
<a href="https://docs.rs/salvo"><img alt="Documentation" src="https://docs.rs/salvo/badge.svg" /></a>
<a href="https://github.com/rust-secure-code/safety-dance/"><img alt="unsafe forbidden" src="https://img.shields.io/badge/unsafe-forbidden-success.svg" /></a>
<a href="https://blog.rust-lang.org/2024/07/25/Rust-1.80.0.html"><img alt="Rust Version" src="https://img.shields.io/badge/rust-1.80%2B-blue" /></a>
<br>
<a href="https://salvo.rs">
<img alt="Website" src="https://img.shields.io/badge/https-salvo.rs-%23f00" />
</a>
<a href="https://codecov.io/gh/salvo-rs/salvo"><img alt="codecov" src="https://codecov.io/gh/salvo-rs/salvo/branch/main/graph/badge.svg" /></a>
<a href="https://crates.io/crates/salvo"><img alt="Download" src="https://img.shields.io/crates/d/salvo.svg" /></a>
<img alt="License" src="https://img.shields.io/crates/l/salvo.svg" />
</p>
</div>
Salvo is an extremely simple and powerful Rust web backend framework. Only basic Rust knowledge is required to develop backend services.
## ð¯ Features
- Built with [Hyper 1](https://crates.io/crates/hyper) and [Tokio](https://crates.io/crates/tokio);
- HTTP1, HTTP2 and **HTTP3**;
- Unified middleware and handle interface;
- Router can be nested infinitely, and multiple middlewares can be attached to any router;
- Integrated Multipart form processing;
- Support WebSocket, WebTransport;
- Support OpenAPI, generate OpenAPI data automatic;
- Support Acme, automatically get TLS certificate from [let's encrypt](https://letsencrypt.org/);
- Support Tower Service and Layer;
## â¡ï¸ Quick Start
You can view samples [here](https://github.com/salvo-rs/salvo/tree/main/examples), or view [official website](https://salvo.rs).
### Hello World with ACME and HTTP3
**It only takes a few lines of code to implement a server that supports ACME to automatically obtain certificates and supports HTTP1, HTTP2, and HTTP3 protocols.**
```rust
use salvo::prelude::*;
#[handler]
async fn hello(res: &mut Response) {
res.render(Text::Plain("Hello World"));
}
#[tokio::main]
async fn main() {
let mut router = Router::new().get(hello);
let listener = TcpListener::new("0.0.0.0:443")
.acme()
.add_domain("test.salvo.rs") // Replace this domain name with your own.
.http01_challege(&mut router).quinn("0.0.0.0:443");
let acceptor = listener.join(TcpListener::new("0.0.0.0:80")).bind().await;
Server::new(acceptor).serve(router).await;
}
```
### Middleware
There is no difference between Handler and Middleware, Middleware is just Handler. **So you can write middlewares without to know concepts like associated type, generic type. You can write middleware if you can write function!!!**
```rust
use salvo::http::header::{self, HeaderValue};
use salvo::prelude::*;
#[handler]
async fn add_header(res: &mut Response) {
res.headers_mut()
.insert(header::SERVER, HeaderValue::from_static("Salvo"));
}
```
Then add it to router:
```rust
Router::new().hoop(add_header).get(hello)
```
This is a very simple middleware, it adds `Header` to `Response`, view [full source code](https://github.com/salvo-rs/salvo/blob/main/examples/middleware-add-header/src/main.rs).
### Chainable tree routing system
Normally we write routing like thisï¼
```rust
Router::with_path("articles").get(list_articles).post(create_article);
Router::with_path("articles/<id>")
.get(show_article)
.patch(edit_article)
.delete(delete_article);
```
Often viewing articles and article lists does not require user login, but creating, editing, deleting articles, etc. require user login authentication permissions. The tree-like routing system in Salvo can meet this demand. We can write routers without user login together:
```rust
Router::with_path("articles")
.get(list_articles)
.push(Router::with_path("<id>").get(show_article));
```
Then write the routers that require the user to login together, and use the corresponding middleware to verify whether the user is logged in:
```rust
Router::with_path("articles")
.hoop(auth_check)
.push(Router::with_path("<id>").patch(edit_article).delete(delete_article));
```
Although these two routes have the same `path("articles")`, they can still be added to the same parent route at the same time, so the final route looks like this:
```rust
Router::new()
.push(
Router::with_path("articles")
.get(list_articles)
.push(Router::with_path("<id>").get(show_article)),
)
.push(
Router::with_path("articles")
.hoop(auth_check)
.push(Router::with_path("<id>").patch(edit_article).delete(delete_article)),
);
```
`<id>` matches a fragment in the path, under normal circumstances, the article `id` is just a number, which we can use regular expressions to restrict `id` matching rules, `r"<id:/\d+/>"`.
You can also use `<**>`, `<*+>` or `<*?>` to match all remaining path fragments. In order to make the code more readable, you can also add appropriate name to make the path semantics more clear, for example: `<**file_path>`.
Some regular expressions for matching paths need to be used frequently, and it can be registered in advance, such as GUID:
```rust
PathFilter::register_wisp_regex(
"guid",
Regex::new("[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}").unwrap(),
);
```
This makes it more concise when path matching is required:
```rust
Router::with_path("<id:guid>").get(index)
```
View [full source code](https://github.com/salvo-rs/salvo/blob/main/examples/routing-guid/src/main.rs)
### File upload
We can get file async by the function `file` in `Request`:
```rust
#[handler]
async fn upload(req: &mut Request, res: &mut Response) {
let file = req.file("file").await;
if let Some(file) = file {
let dest = format!("temp/{}", file.name().unwrap_or_else(|| "file".into()));
if let Err(e) = tokio::fs::copy(&file.path, Path::new(&dest)).await {
res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
} else {
res.render("Ok");
}
} else {
res.status_code(StatusCode::BAD_REQUEST);
}
}
```
### Extract data from request
You can easily get data from multiple different data sources and assemble it into the type you want. You can define a custom type first, for example:
```rust
#[derive(Serialize, Deserialize, Extractible, Debug)]
/// Get the data field value from the body by default.
#[salvo(extract(default_source(from = "body")))]
struct GoodMan<'a> {
/// The id number is obtained from the request pa
没有合适的资源?快使用搜索试试~ 我知道了~
Rust:Salvo 是一个极其简单易用却又功能强大的 Rust Web 后端框架.zip
共660个文件
rs:333个
toml:107个
txt:42个
需积分: 5 0 下载量 61 浏览量
2024-08-01
15:03:39
上传
评论
收藏 17.08MB ZIP 举报
温馨提示
Rust:Salvo 是一个极其简单易用却又功能强大的 Rust Web 后端框架.zip
资源推荐
资源详情
资源评论
收起资源包目录
Rust:Salvo 是一个极其简单易用却又功能强大的 Rust Web 后端框架.zip (660个子文件)
work.txt.br 499B
.eslintrc.cjs 415B
.eslintrc.cjs 415B
openssl.cnf 761B
config 240B
swagger-ui.css 149KB
skeleton.css 11KB
normalize.css 8KB
client.css 1KB
client.css 1KB
style.css 1KB
Header.css 572B
Header.css 572B
App.css 564B
App.css 558B
App.css 558B
index.css 408B
index.css 408B
index.css 366B
dev.db 24KB
dev.db-journal 9KB
FETCH_HEAD 13KB
.gitignore 334B
.gitignore 310B
.gitignore 253B
.gitignore 253B
work.txt.gz 524B
HEAD 130B
HEAD 21B
skirt.html 3KB
play.html 3KB
index.html 3KB
oauth2-redirect.html 3KB
client.html 3KB
client.html 3KB
index.html 2KB
index.html 483B
index.html 483B
fallback.html 59B
index.html 56B
index.html 56B
hello.html 18B
favicon.ico 4KB
favicon.ico 4KB
favicon.ico 4KB
pack-43fe204ec8c7bc5848c7fd0197ccc8d7052d915f.idx 872KB
index 64KB
swagger-ui-bundle.js 1.39MB
swagger-ui-es-bundle.js 1.39MB
swagger-ui.js 331KB
swagger-ui-standalone-preset.js 225KB
client.js 5KB
client.js 5KB
index.js 535B
App.js 528B
reportWebVitals.js 362B
vite.config.js 260B
vite.config.js 260B
App.test.js 246B
setupTests.js 241B
package.json 812B
package.json 737B
package.json 737B
manifest.json 492B
manifest.json 491B
manifest.json 491B
App.jsx 896B
App.jsx 896B
Header.jsx 868B
Header.jsx 868B
main.jsx 819B
main.jsx 819B
NoMatch.jsx 232B
NoMatch.jsx 232B
Layout.jsx 187B
Layout.jsx 187B
.keep 0B
LICENSE-APACHE 11KB
LICENSE-MIT 1KB
main 144B
main 130B
main 41B
derive_to_schema.md 20KB
endpoint.md 18KB
README.md 11KB
README.zh-hant.md 11KB
README.zh-hans.md 11KB
README.osc.md 11KB
derive_to_parameters.md 11KB
derive_to_response.md 7KB
derive_to_responses.md 7KB
README.md 3KB
lib.md 3KB
ECOSYSTEM.md 3KB
README.md 1KB
README.md 730B
bug_report.md 665B
README.md 656B
README.md 613B
feature_request.md 595B
共 660 条
- 1
- 2
- 3
- 4
- 5
- 6
- 7
资源评论
baidu_16992441
- 粉丝: 311
- 资源: 1041
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功