Anglais 简体中文 繁體中文



Salvo est un cadre backend Web de rouille extrêmement simple et puissant. Seules les connaissances de base de la rouille sont nécessaires pour développer des services backend.
Vous pouvez consulter des échantillons ici ou consulter le site officiel.
Il ne faut que quelques lignes de code pour implémenter un serveur qui prend en charge ACME pour obtenir automatiquement des certificats, et il prend en charge les protocoles HTTP1, HTTP2 et HTTP3.
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_challenge ( & 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 ;
}Il n'y a pas de différence entre un gestionnaire et un middleware, un middleware n'est qu'un gestionnaire. Vous pouvez écrire des middleware sans connaître des concepts comme les types associés et les types génériques. Si vous pouvez écrire une fonction, vous pouvez écrire middleware !!!
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" ) ) ;
}Puis ajoutez-le au routeur:
Router :: new ( ) . hoop ( add_header ) . get ( hello ) Il s'agit d'un middleware très simple, il ajoute un Header à la Response , afficher le code source complet.
Normalement, nous écrivons le routage comme ceci:
Router :: with_path ( "articles" ) . get ( list_articles ) . post ( create_article ) ;
Router :: with_path ( "articles/<id>" )
. get ( show_article )
. patch ( edit_article )
. delete ( delete_article ) ;Souvent, quelque chose comme la visualisation d'articles et de listes d'articles ne nécessite pas de connexion des utilisateurs, mais de création, d'édition, de supprimer des articles, etc. nécessitent des autorisations d'authentification de connexion des utilisateurs. Le système de routage en forme d'arbre à Salvo peut répondre à cette demande. Nous pouvons écrire des routeurs sans connexion utilisateur ensemble:
Router :: with_path ( "articles" )
. get ( list_articles )
. push ( Router :: with_path ( "<id>" ) . get ( show_article ) ) ;Ensuite, écrivez les routeurs qui obligent l'utilisateur à se connecter ensemble et utilisez le middleware correspondant pour vérifier si l'utilisateur est connecté:
Router :: with_path ( "articles" )
. hoop ( auth_check )
. push ( Router :: with_path ( "<id>" ) . patch ( edit_article ) . delete ( delete_article ) ) ; Bien que ces deux itinéraires aient le même path("articles") , ils peuvent toujours être ajoutés à la même route parentale en même temps, donc l'itinéraire final ressemble à ceci:
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> correspond à un fragment dans le chemin, dans des circonstances normales, l' id de l'article n'est qu'un nombre, que nous pouvons utiliser des expressions régulières pour restreindre les règles de correspondance id , r"<id:/d+/>" .
Vous pouvez également utiliser <**> , <*+> ou <*?> Pour correspondre à tous les fragments de chemin restants. Afin de rendre le code plus lisible, vous pouvez également ajouter un nom approprié pour rendre la sémantique de chemin plus claire, par exemple: <**file_path> .
Certaines expressions régulières pour les chemins de correspondance doivent être utilisées fréquemment, et elles peuvent être enregistrées à l'avance, telles que GUID:
PathFilter :: register_wisp_regex (
"guid" ,
Regex :: new ( "[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}" ) . unwrap ( ) ,
) ;Cela le rend plus concis lorsque la correspondance de chemin est requise:
Router :: with_path ( "<id:guid>" ) . get ( index )Afficher le code source complet
Nous pouvons obtenir un fichier asynchrone par le file de fonction dans Request :
# [ 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 ) ;
}
}Vous pouvez facilement obtenir des données à partir de plusieurs sources de données différentes et les assembler dans le type que vous souhaitez. Vous pouvez d'abord définir un type personnalisé, par exemple:
# [ 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 path parameter, and the data is automatically parsed as i64 type.
# [ salvo ( extract ( source ( from = "param" ) ) ) ]
id : i64 ,
/// Reference types can be used to avoid memory copying.
username : & ' a str ,
first_name : String ,
last_name : String ,
} Ensuite, dans Handler vous pouvez obtenir les données comme ceci:
# [ handler ]
async fn edit ( req : & mut Request ) {
let good_man : GoodMan < ' _ > = req . extract ( ) . await . unwrap ( ) ;
}Vous pouvez même transmettre le type directement à la fonction en tant que paramètre, comme ceci:
# [ handler ]
async fn edit < ' a > ( good_man : GoodMan < ' a > ) {
res . render ( Json ( good_man ) ) ;
}Afficher le code source complet
Un soutien parfait à OpenAPI peut être réalisé sans apporter de modifications significatives au projet.
# [ derive ( Serialize , Deserialize , ToSchema , Debug ) ]
struct MyObject < T : ToSchema + std :: fmt :: Debug > {
value : T ,
}
# [ endpoint ]
async fn use_string ( body : JsonBody < MyObject < String > > ) -> String {
format ! ( "{:?}" , body )
}
# [ endpoint ]
async fn use_i32 ( body : JsonBody < MyObject < i32 > > ) -> String {
format ! ( "{:?}" , body )
}
# [ endpoint ]
async fn use_u64 ( body : JsonBody < MyObject < u64 > > ) -> String {
format ! ( "{:?}" , body )
}
# [ tokio :: main ]
async fn main ( ) {
tracing_subscriber :: fmt ( ) . init ( ) ;
let router = Router :: new ( )
. push ( Router :: with_path ( "i32" ) . post ( use_i32 ) )
. push ( Router :: with_path ( "u64" ) . post ( use_u64 ) )
. push ( Router :: with_path ( "string" ) . post ( use_string ) ) ;
let doc = OpenApi :: new ( "test api" , "0.0.1" ) . merge_router ( & router ) ;
let router = router
. push ( doc . into_router ( "/api-doc/openapi.json" ) )
. push ( SwaggerUi :: new ( "/api-doc/openapi.json" ) . into_router ( "swagger-ui" ) ) ;
let acceptor = TcpListener :: new ( "127.0.0.1:5800" ) . bind ( ) . await ;
Server :: new ( acceptor ) . serve ( router ) . await ;
}Salvo CLI est un outil de ligne de commande qui simplifie la création de nouveaux projets Salvo, des modèles de support pour les API Web, les sites Web, les bases de données (y compris SQLite, PostgreSQL et MySQL via SQLX, Seaorm, Diesel, Rbatis) et des middleware de base. Vous pouvez utiliser Salvo-Cli pour créer un nouveau projet Salvo:
cargo install salvo-clisalvo new project_nameVous pouvez trouver plus d'exemples dans le dossier Exemples. Vous pouvez exécuter ces exemples avec la commande suivante:
cd examples
cargo run --bin example-basic-auth Vous pouvez utiliser n'importe quel exemple de nom que vous souhaitez exécuter au lieu de basic-auth ici.
Le résultat des tests de référence peut être trouvé à partir d'ici:
https://web-frameworks-benchmark.netlify.app/result?l=rust
https://www.techempower.com/benchmarks/#section=data-r22
Salvo est un projet open source. Si vous souhaitez soutenir Salvo, vous pouvez m'acheter un café ici .
Salvo est autorisé sous l'un ou l'autre des
Licence Apache, version 2.0, (Licence-apache ou http://www.apache.org/licenses/license-2.0).
Licence MIT (licence-mit ou http://openseource.org/licenses/mit).