替换url部分_actixweb 中的 URL 调度(3) actixweb 开发指南

ceec3ac8ec1d996828ee1f424801a6f0.png

actix-web 中的 URL 调度(2) 中介绍了资源模式语法、作用域路由、匹配信息,以及路径信息提取部分,在 actix-web 中的 URL 调度(3) 中,我们将继续介绍 actix-web 中生成资源 URL、外部资源、路径规范化,以及重定向到附加斜杠的路由、使用作用域前缀组合应用、自定义路由卫语句、修改卫语句的值,以及更改默认的 Not Found 响应等剩余部分。

生成资源 URL

使用 HttpRequest.url_for() 方法,生成基于资源模式的 URL。例如,如果您配置了一个名称为“foo”,且模式为“{a}/{b}/{c}”的资源,则可以执行以下操作:

use actix_web::{get, guard, http::header, HttpRequest, HttpResponse, Result};#[get("/test/")]async fn index(req: HttpRequest) -> Result {    let url = req.url_for("foo", &["1", "2", "3"])?; //     Ok(HttpResponse::Found()        .header(header::LOCATION, url.as_str())        .finish())}#[actix_web::main]async fn main() -> std::io::Result {    use actix_web::{web, App, HttpServer};    HttpServer::new(|| {        App::new()            .service(                web::resource("/test/{a}/{b}/{c}")                    .name("foo") //                     .guard(guard::Get())                    .to(|| HttpResponse::Ok()),            )            .service(index)    })    .bind("127.0.0.1:8080")?    .run()    .await}

这会返回类似 http://example.com/test/1/2/3 的字符串(协议和主机名仅为示例)。url_for() 返回结构体 Url 对象,你可以对 url 进行修改(添加查询参数、锚点等)。只有已命名资源调用可以 url_for() 方法,否则返回错误。

外部资源

有效的资源 URL,可以注册为外部资源。外部资源仅用于生成 URL,在请求时,从不考虑进行匹配。

use actix_web::{get, App, HttpRequest, HttpServer, Responder};#[get("/")]async fn index(req: HttpRequest) -> impl Responder {    let url = req.url_for("youtube", &["oHg5SJYRHA0"]).unwrap();    assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0");    url.into_string()}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .service(index)            .external_resource("youtube", "https://youtube.com/watch/{video_id}")    })    .bind("127.0.0.1:8080")?    .run()    .await}

4edcae881fa617197023be45e045719f.png

路径规范化,以及重定向到附加斜杠的路由

路径规范化意味着:

  • 对路径附加尾部斜杠;

  • 规范路径中的斜杠,用一个斜杠替换连续的多个斜杠。

路径规范化处理程序一旦找到正确解析的路径,就会立刻返回。如果启用了所有规范化条件,则其顺序为:1)合并,2)合并和追加,以及 3)追加。如果路径至少在其中一个条件下解析,它将重定向到新路径。

use actix_web::{middleware, HttpResponse};async fn index() -> HttpResponse {    HttpResponse::Ok().body("Hello")}#[actix_web::main]async fn main() -> std::io::Result {    use actix_web::{web, App, HttpServer};    HttpServer::new(|| {        App::new()            .wrap(middleware::NormalizePath::default())            .route("/resource/", web::to(index))    })    .bind("127.0.0.1:8080")?    .run()    .await}

示例中,//resource/// 将会被重定向为 /resource/。

上述示例中,为所有方法都注册了路径规范化处理程序,但你不应依赖于这种机制去重定向 POST 请求。附加斜杠的 Not Found 路径,其重定向会丢失原始请求中的所有 POST 数据,将 POST 请求转换为 GET 请求。

可以仅对 GET 请求注册路径规范化处理程序:

use actix_web::{get, http::Method, middleware, web, App, HttpServer};#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .wrap(middleware::NormalizePath::default())            .service(index)            .default_service(web::route().method(Method::GET))    })    .bind("127.0.0.1:8080")?    .run()    .await}

使用作用域前缀组合应用

web::scope() 方法允许设置特定的应用程序作用域。此作用域表示一个资源前缀,该前缀将预置到由资源配置添加的所有资源模式中。这可以用来帮助装载一组路由到新的 URL 路径,而与其包含的可调用 URL 路径不同,同时仍保持相同的资源名称。

例如:

use actix_web::{get, http::Method, middleware, web, App, HttpServer};#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .wrap(middleware::NormalizePath::default())            .service(index)            .default_service(web::route().method(Method::GET))    })    .bind("127.0.0.1:8080")?    .run()    .await}

在上面的示例中,show_users 路由将具有有效路由模式 /users/show,而不是 /show,因为应用程序作用域将预先添加到路由模式中。只有当 URL 路径匹配 /users/show,并且使用路由名称 show_users 调用 HttpRequest.url_for() 函数时,它将生成具有相同路径的 URL。

自定义路由卫语句

可以将卫语句视作为一个简单的函数,它接受请求 对象引用,并返回 true 或 false。从形式上讲,卫语句是实现 Guard trait 的任何对象。actix 提供了几个断言,详细了解请可以查看 API 文档的函数章节。

下面示例是一个简单的卫语句,用于检查请求是否包含特定的消息头 :

use actix_web::{dev::RequestHead, guard::Guard, http, HttpResponse};struct ContentTypeHeader;impl Guard for ContentTypeHeader {    fn check(&self, req: &RequestHead) -> bool {        req.headers().contains_key(http::header::CONTENT_TYPE)    }}#[actix_web::main]async fn main() -> std::io::Result {    use actix_web::{web, App, HttpServer};    HttpServer::new(|| {        App::new().route(            "/",            web::route()                .guard(ContentTypeHeader)                .to(|| HttpResponse::Ok()),        )    })    .bind("127.0.0.1:8080")?    .run()    .await}

上述示例中,只有当请求包含 CONTENT-TYPE 消息头时,才会调用index handler。

卫语句不能访问或修改请求对象,但是可以在请求扩展中存储额外的信息。

修改卫语句的值

通过将断言值包裹在 Not 断言中,可以反转任何断言值的含义。例如,如果要为除 GET 之外的所有方法返回 METHOD NOT ALLOWED 响应:

use actix_web::{guard, web, App, HttpResponse, HttpServer};#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new().route(            "/",            web::route()                .guard(guard::Not(guard::Get()))                .to(|| HttpResponse::MethodNotAllowed()),        )    })    .bind("127.0.0.1:8080")?    .run()    .await}

如果要匹配所提供卫语句列表中的任意一个,可以使用 Any 卫语句。即:

#![allow(unused)]fn main() {guard::Any(guard::Get()).or(guard::Post())}

如果要匹配所提供的卫语句列表中的全部项,可以使用 All 卫语句。即:

#![allow(unused)]fn main() {guard::All(guard::Get()).and(guard::Header("content-type", "plain/text"))}

更改默认的 Not Found 响应

如果在路由表中不能发现路径模式,或资源找不到可匹配的路由,则会使用默认资源。默认的响应是 NOT FOUND,我们可以使用 App::default_service() 方法重写 NOT FOUND 响应。此方法通过 App::service() 方法接受配置函数,与普通资源配置方法相同。

#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new()            .service(web::resource("/").route(web::get().to(index)))            .default_service(                web::route()                    .guard(guard::Not(guard::Get()))                    .to(|| HttpResponse::MethodNotAllowed()),            )    })    .bind("127.0.0.1:8080")?    .run()    .await}

因微信公众号阅读体验和篇幅限制,内容可能有所删减。访问芽之家书籍资料,或者 actix-web 开发指南站点 https://actix-web.budshome.com,可以进行更详细的了解,以及获取更多技术资料。

5364f60836d376619e7ceac63b77b0eb.png 请点击阅读原文进行更详细的学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值