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

本文深入探讨了actix-web的URL调度,包括资源模式语法,如可变部分和正则表达式匹配,以及作用域路由、匹配信息的获取和路径信息提取的方法。通过实例展示了如何有效地配置和使用actix-web的路由系统。
摘要由CSDN通过智能技术生成

a3ac0eb4f487d7efe49741c057f88e51.png

actix-web 中的 URL 调度(1) 中介绍了资源配置、路由配置,以及路由匹配,在 actix-web 中的 URL 调度(2) 中,我们将继续介绍 actix-web 中资源模式语法、作用域路由、匹配信息,以及路径信息提取部分。

资源模式语法

在模式参数匹配中,actix 使用的模式匹配语法简单明确。

在路由配置中,使用的模式可以以斜杠字符 / 开头。如果模式不是以斜杠字符 / 开头,匹配时则会在其前面加上一个隐式斜杠。例如,以下模式是等效的:

{foo}/bar/baz

以及:

/{foo}/bar/baz

可变部分(替换标记)以 {id} 的形式指定,这意味着——下一个斜杠字符 / 之前,接受任意字符,并将其用作 HttpRequest.match_info() 对象的名称。

模式中的替换标记,匹配正则表达式 [^{}/]+。

匹配信息(match_info)是 Params 对象,表示以路由模式为依据,从 URL 中提取的动态部分。匹配信息(match_info)也可以作为请求的匹配信息,如 request.match_info。下面示例模式中,定义了一个文本段(foo)和两个替换标记(baz 和 bar):

foo/{baz}/{bar}

此模式将匹配如下 URL,可生成以下匹配信息:

foo/1/2        -> Params {'baz':'1', 'bar':'2'}foo/abc/def    -> Params {'baz':'abc', 'bar':'def'}

但是,下述模式不会被匹配:

foo/1/2/        -> No match (trailing slash)bar/abc/def     -> First segment literal mismatch

在路径段正则模式中,替换标记仅匹配到路径段中的第一个非字母数字字符。例如,如果使用这种路由模式:

foo/{name}.html

文本路径 /foo/biz.html 将匹配上面的路由模式,匹配结果为 Params{'name': 'biz'}。但是,文本路径 /foo/biz 不会匹配,因为末尾未包含 .html 字段。

如果两种文本路径都要匹配,可以使用两个替换标记:

foo/{name}.{ext}

文本路径 /foo/biz.html 将匹配上面的路由模式,匹配结果为 Params{’name’: ‘biz’, ‘ext’: ‘html’}。这样写是因为在替换标记 {name} 和 {ext} 之间,存在一个文本部分 .(点号)。

替换标记可以可选地指定一个正则表达式,该表达式将用于决定路径段是否应与替换标记匹配。要指定替换标记仅匹配正则表达式定义的特定字符集,必须对替换标记语法做一些形式上的扩展。在大括号 {} 中,替换标记名称后,必须跟随冒号 :,然后是正则表达式。与替换标记 1+ 关联的默认正则表达式,可匹配一个或多个非斜杠字符。例如,底层的替换标记 {foo} 可以更详细地写为 {foo:1+}。你可以将此更改为具体的正则表达式,以匹配具体的字符序列。比如更改为 {foo:\d+},将仅匹配数字。

路径段必须至少包含一个字符,才能匹配路径的替换标记。例如,对于 URL 路径 /abc/:

    /abc/{foo} 不会匹配;    /{foo}/ 可以匹配。

注意:在匹配模式前,将对 URL 路径去除引号,并解码为有效的 unicode 字符串;且代表路径段的匹配值,也将是去除引号的 URL。

例如,对于如下模式:

foo/{bar}

在匹配如下 URL 时:

http://example.com/foo/La%20Pe%C3%B1a

匹配字典如下所示(URL 解码后的值):

Params{'bar': 'La Pe\xf1a'}

路径段中的文本字符串代表路径的解码值,以提供给 actix。你不会希望在模式中使用 URL 编码值。例如,不是这样的 URL 编码值:

/Foo%20Bar/{baz}

你会希望使用这样的值:

/Foo Bar/{baz}

但这样做有可能得到“尾部匹配(tail match)”,为此,必须使用自定义正则表达式。

foo/{bar}/{tail:.*}

上述模式可匹配如下 URL,并生成如下匹配信息:

foo/1/2/           -> Params{'bar':'1', 'tail': '2/'}foo/abc/def/a/b/c  -> Params{'bar':u'abc', 'tail': 'def/a/b/c'}

作用域路由

作用域可以帮助你组织路由,以共享共用的根路径。作用域可以嵌套。

比如,你希望组织一组路径,用于查看 “Users” 端资源。这些路径可能包括:

  • /users

  • /users/show

  • /users/show/{id}

    这些路径的作用域布局如下所示:
#[get("/show")]async fn show_users() -> HttpResponse {    HttpResponse::Ok().body("Show users")}#[get("/show/{id}")]async fn user_detail(path: web::Pathu32,)>)     HttpResponse::Ok().body(format!("User detail: {}", path.into_inner().0))}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| {        App::new().service(            web::scope("/users")                .service(show_users)                .service(user_detail),        )    })    .bind("127.0.0.1:8080")?    .run()    .await}

作用域 路径可以包含可变路径段,与非作用域路径用法一致。

你可以使用 HttpRequest::match_info() 方法获取可变路径段,Path 提取器也可以提取作用域层级的变量段。

6aa8b4e7f7b6c129770f543c6f9b31ee.png

匹配信息

所有代表路径段的匹配值,都可以使用 HttpRequest::match_info 方法获得。Path::get() 方法可用于检索特定值。

use actix_web::{get, App, HttpRequest, HttpServer, Result};#[get("/a/{v1}/{v2}/")]async fn index(req: HttpRequest) -> Result<String> {    let v1: u8 = req.match_info().get("v1").unwrap().parse().unwrap();    let v2: u8 = req.match_info().query("v2").parse().unwrap();    let (v3, v4): (u8, u8) = req.match_info().load().unwrap();    Ok(format!("Values {} {} {} {}", v1, v2, v3, v4))}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| App::new().service(index))        .bind("127.0.0.1:8080")?        .run()        .await}

示例中的路径 ‘/a/1/2/’,其中的 v1 和 v2 两个值将被解析为 “1” 和 “2”。

可以由路径尾部的参数创建 PathBuf,PathBuf 返回值经百分比解码(URL 解码)。如果分段是 ..,则跳过前一个分段(如果存在)。

出于安全目的,如果分段满足以下任一条件,则返回一个 Err,表示该条件已满足:

  • 解码段的开头为(任一):.(不包括 ..),*

  • 解码段的结尾为(任一)::,>,<

  • 解码段包含(任一):/

  • Windows 环境,解码段包含(任一):\

  • 百分比编码(URL 编码)导致的无效 UTF8。

基于上述条件,从请求路径参数解析的 PathBuf,可以安全地在路径内插入,或用作路径的后缀,而无需额外检查。
use actix_web::{get, App, HttpRequest, HttpServer, Result};use std::path::PathBuf;#[get("/a/{tail:.*}")]async fn index(req: HttpRequest) -> Result {    let path: PathBuf = req.match_info().query("tail").parse().unwrap();    Ok(format!("Path {:?}", path))}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| App::new().service(index))        .bind("127.0.0.1:8080")?        .run()        .await}

路径信息提取

actix 提供类型安全的路径信息提取的功能。使用 Path 结构体提取路径信息后,目标类型可以定义为几种不同的形式。最简单的方式是使用元组(tuple)类型,元组中的每个元素必须对应于路径模式中的一个元素。也就是说,你可以将路径模式 /{id}/{username}/ 与类型 Path 成功匹配,但是与类型 Path 的匹配就会失败。

use actix_web::{get, web, App, HttpServer, Result};#[get("/{username}/{id}/index.html")] // async fn index(info: web::PathString, u32)>) -> Result<    let info = info.into_inner();    Ok(format!("Welcome {}! id: {}", info.0, info.1))}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| App::new().service(index))        .bind("127.0.0.1:8080")?        .run()        .await}

也可以将路径模式信息提取到结构体中。下述示例中,结构体必须反序列化,实现 serde crate 的 Deserialize trait。

use actix_web::{get, web, App, HttpServer, Result};use serde::Deserialize;#[derive(Deserialize)]struct Info {    username: String,}// extract path info using serde#[get("/{username}/index.html")] // async fn index(info: web::Path) -> Result {    Ok(format!("Welcome {}!", info.username))}#[actix_web::main]async fn main() -> std::io::Result {    HttpServer::new(|| App::new().service(index))        .bind("127.0.0.1:8080")?        .run()        .await}

Query 结构体为请求查询参数提供了类似的功能。

未完待续,……

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值