Englisch 简体中文 繁體中文



Salvo ist ein extrem einfaches und leistungsstarkes Rost -Web -Backend -Framework. Um Backend -Dienste zu entwickeln, sind nur grundlegende Rostkenntnisse erforderlich.
Sie können hier Muster anzeigen oder die offizielle Website anzeigen.
Es braucht nur wenige Codezeilen, um einen Server zu implementieren, der ACME dazu unterstützt, automatisch Zertifikate zu erhalten, und es unterstützt HTTP1-, HTTP2- und HTTP3 -Protokolle.
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 ;
}Es gibt keinen Unterschied zwischen einem Handler und einer Middleware, einer Middleware ist nur ein Handler. Sie können Middleware schreiben, ohne Konzepte wie zugehörige Typen und generische Typen zu kennen. Wenn Sie eine Funktion schreiben können, können Sie Middleware schreiben !!!
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" ) ) ;
}Dann fügen Sie es zu Router hinzu:
Router :: new ( ) . hoop ( add_header ) . get ( hello ) Dies ist eine sehr einfache Middleware, die der Response einen Header hinzufügt, den vollständigen Quellcode anzeigen.
Normalerweise schreiben wir so Routing:
Router :: with_path ( "articles" ) . get ( list_articles ) . post ( create_article ) ;
Router :: with_path ( "articles/<id>" )
. get ( show_article )
. patch ( edit_article )
. delete ( delete_article ) ;Oft erfordert so etwas wie das Anzeigen von Artikeln und Artikellisten keine Benutzeranmeldung, sondern das Erstellen, Bearbeiten, Löschen von Artikeln usw. Erfordern sich die Berechtigungen für Benutzeranmeldungsauthentifizierung. Das baumartige Routing-System in Salvo kann diese Nachfrage erfüllen. Wir können Router ohne Nutzer zusammenschreiben:
Router :: with_path ( "articles" )
. get ( list_articles )
. push ( Router :: with_path ( "<id>" ) . get ( show_article ) ) ;Schreiben Sie dann den Routern, bei denen der Benutzer sich anmelden muss, und überprüft, ob der Benutzer angemeldet ist:
Router :: with_path ( "articles" )
. hoop ( auth_check )
. push ( Router :: with_path ( "<id>" ) . patch ( edit_article ) . delete ( delete_article ) ) ; Obwohl diese beiden Routen den gleichen path("articles") , können sie gleichzeitig zur gleichen übergeordneten Route hinzugefügt werden, sodass die endgültige Route so aussieht:
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> entspricht einem Fragment auf dem Pfad unter normalen Umständen, die Artikel id ist nur eine Nummer, die wir reguläre Ausdrücke verwenden können, um id -Übereinstimmungsregeln zu beschränken, r"<id:/d+/>" .
Sie können auch <**> , <*+> oder <*?> Verwenden, um alle verbleibenden Pfadfragmente zu entsprechen. Um den Code lesbarer zu gestalten, können Sie auch den geeigneten Namen hinzufügen, um die Pfadsemantik klarer zu machen, z. B. <**file_path> .
Einige regelmäßige Ausdrücke für passende Pfade müssen häufig verwendet werden und können im Voraus registriert werden, wie z. B. 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 ( ) ,
) ;Dies macht es prägnanter, wenn eine Pfadübereinstimmung erforderlich ist:
Router :: with_path ( "<id:guid>" ) . get ( index )Volle Quellcode anzeigen
Wir können die Datei asynchronisiert durch die file in Request erhalten:
# [ 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 ) ;
}
}Sie können leicht Daten aus mehreren verschiedenen Datenquellen abrufen und sie in den gewünschten Typ zusammenstellen. Sie können zuerst einen benutzerdefinierten Typ definieren, zum Beispiel:
# [ 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 ,
} In Handler können Sie die Daten wie diese erhalten:
# [ handler ]
async fn edit ( req : & mut Request ) {
let good_man : GoodMan < ' _ > = req . extract ( ) . await . unwrap ( ) ;
}Sie können den Typ sogar direkt an die Funktion als Parameter übergeben:
# [ handler ]
async fn edit < ' a > ( good_man : GoodMan < ' a > ) {
res . render ( Json ( good_man ) ) ;
}Volle Quellcode anzeigen
Eine perfekte Unterstützung für OpenAPI kann erreicht werden, ohne wesentliche Änderungen am Projekt vorzunehmen.
# [ 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 ist ein Befehlszeilen-Tool, das die Erstellung neuer Salvo-Projekte und Vorlagen für Web-APIs, Websites, Datenbanken (einschließlich SQLite, Postgresql und MySQL über SQLX, Seerform, Diesel, Rbatis) und grundlegende Middleware vereinfacht. Sie können Salvo-Cli verwenden, um ein neues Salvo-Projekt zu erstellen:
cargo install salvo-clisalvo new project_nameSie können weitere Beispiele in Beispielen finden. Sie können diese Beispiele mit dem folgenden Befehl ausführen:
cd examples
cargo run --bin example-basic-auth Sie können jeden Beispielnamen verwenden, den Sie hier ausführen möchten, anstatt von basic-auth .
Das Benchmark -Testgebnis finden Sie von hier aus:
https://web-frameworks-benchmark.netlify.app/result?l=rust
https://www.techempower.com/benchmarks/#section=data-r22
Salvo ist ein Open -Source -Projekt. Wenn Sie Salvo unterstützen möchten, können Sie mir hier einen Kaffee kaufen .
Salvo ist unter einem von lizenziert
Apache-Lizenz, Version 2.0, (Lizenz-apache oder http://www.apache.org/licenses/license-2.0).
MIT-Lizenz (Lizenz- oder http://opensource.org/licenses/mit).