rust web框架rocket指南——概要

概要

Rocket 提供最基础的架构来构建rust服务端应用:剩下的取决于你自己。简而言之,Rocket提供路由,请求前置处理和相应后置处理。至于,请求前置如何处理,相应后置如何处理,请求如何处理,都是你的业务代码决定的。

生命周期

Rocket的主要任务时监听新来的web请求,分发这些请求到业务代码,并且返回响应到客户端。我们把从请求到响应的过程叫做生命周期。我们把生命周期总结为一下几个步骤:

  1. 路由
    Rocket 会把新来的HTTP请求解析为你的代码可以操作的rust结构。并且通过匹配你程序中声明的路由属性,来检测,应该调用那个一个处理器。
  2. 验证
    Rocket在匹配了路由以后就会对请求的数据做类型及有效性的验证。如果验证失败,则Rocket会把请求转到下一个匹配的路由,或者直接调用失败处理器。
  3. 处理器
    请求的数据被验证成功之后,会作为参数来调用绑定在路由上的处理器。作为应用的主要逻辑,在调用结束后,会返回一个响应。
  4. 响应
    返回的响应也是被处理过的。Rocket 会生成合适的HTTP响应并且发送到客户端。这样一个生命周期就结束了。Rocket继续监听新的请求。并为每个请求创建一个生命周期。

这个章节剩余的部分会详述路由部分和Rocket分发请求到请求处理器所需要的组件。之后的章节会详述请求、响应部分和Rocket的其它组件。

路由

Rocket应用都是以路由和处理器为中心。路由由下列组成:

  • 一组参数来匹配新来的请求。
  • 一个处理请求和返回响应的处理器。

处理器是一个简单的函数,接受任意个数的参数并且返回任意类型的结果。

用来匹配的参数包括静态路径、动态路径、路径参数、表单、查询参数、特定的请求格式和 请求体数据。Rocket 利用属性(类似其它语言的装饰器一样),使得路由声明变得加单。路由声明就是给处理器方法添加注解并且有一组参数用来匹配。一个完整的路由声明是像这样的:

#[get("/world")]              // <- route attribute
fn world() -> &'static str {  // <- request handler
      "Hello, world!"
}

这个声明了world路由用来匹配静态路径"/world"GET请求。"world"路由比较简单,不过当构建复杂的应用个的时候,额外的路由参数是必须的。请求 一节里面讲解了构建路由的所有情况。

挂载

在Rocket 能够分发请求到一个路由之前,路由需要先完成挂载。 挂载路由,类似给路由一个命名空间。用 Rocket实例的mount方法来挂载一个路由。Rocket实例通常使用rocket::ignite()静态方法来创建。

mount方法需要:

  • 一个包含一系列路由的命名空间的路径。
  • 一组对应路由的处理器!和生成Rocket应用代码的宏。

例如,挂载之前声明的world路由,我们可以这样写:

rocket::ignite().mount("/hello", routes![world]);

这块代码通过 ignite 函数创建了一个新的Rocket实例,并且将 world路由挂载到了“/hello” 路径下面。
其结果就是,GET请求 “/hello/world”路径就会访问world函数。

命名空间

当一个路由是在root之外的其它模块里声明的,你会在挂载的时候会得到一个异常:

mod other {
    #[get("/world")]
    pub fn world() -> &'static str {
        "Hello, world!"
    }
}

use other::world;

fn main() {
  // error[E0425]: cannot find value `static_rocket_route_info_for_world` in this scope
  rocket::ignite().mount("/hello", routes![world]);
}

这个错误出现是因为 宏 routes! 在生成Rocket代码的时候隐式地将 route的名称 转换为了当前解构里的名称。解决方法是在写路由名称的时候加上模块的名字:

rocket::ignite().mount("/hello", routes![other::world]);

运行

现在Rocket已经有了路由,你可以用launch方法来启动Rocket接受请求。launch用来方法启动服务等待请求。当请求到达时,Rocket 会找到匹配的路由,并将请求分发到该路由的处理器。

通常情况下我们在main方法里调用launch方法。现在我们已经完成了Hello, world!程序,看起来像这样:

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/world")]
fn world() -> &'static str {
    "Hello, world!"
}

fn main() {
    rocket::ignite().mount("/hello", routes![world]).launch();
}

注意到我们添加了#![feature(plugin)]#![plugin(rocket_codegen)]这两行,是告诉Rust我们使用了Rocket的代码生成插件。同样我们将通过extern crate rocketrocket crate(箱)引入了我们的命名空间。最后,我们在main函数里调用了launch 方法。

运行这个程序,控制台会显示内容:

  Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: [logical cores * 2]
    => secret key: generated
    => limits: forms = 32KiB
    => tls: disabled
  Mounting '/hello':
    => GET /hello/world
  Rocket has launched from http://localhost:8000

我们访问 localhost:8000/hello/world,就会看到Hello, world, 正好是我们预期的。

在GitHub上有这个例子一个完整版的crate(箱),只要cargo run 就能运行。 你可以在 GitHub examples directory 中找到更多的例子,涵盖了所有Rocket的特性。

Rocket系列 >>

你可能感兴趣的:(rust web框架rocket指南——概要)