Rust web 框架 axum (二): 返回 HTML form 表单,并处理 post 请求

更新日期: 2023-11-09 阅读次数: 1747 字数: 962 分类: rust

要实现一个小的在线网页工具,最基本的功能就是能够返回一个 HTML form 表单, 让用户能填写数据,然后提交到 rust axum 后台,再将处理后的数据展示出来。

相对 PHP,Python,Go 的 web 框架,Rust 的 web 框架就晦涩很多,下面的示例如果换成其他语言, 在没有任何基础的情况下,估计一小时也能搞定,但是使用 rust axum 这个框架,我还是折腾了一晚上。

主要原因是:

  • axum 的文档太简陋。如果不是 ChatGPT 帮助,我估计给我一天也搞不定。Google 也搜不到太多的资料。
  • rust 语法晦涩,需要具备大量的基础知识

下面示例实现了一些基本的使用场景:

  • 返回纯文本
  • 返回 JSON
  • 返回 HTML
  • 返回 HTML form 表单
  • 显示处理 form 提交数据后的页面

示例代码

use axum::{
    routing::get,
    Router,
    response::{Json, Html},
    Form,
};
use serde_json::{Value, json};
use serde::Deserialize;


#[tokio::main]
async fn main() {
    // build our application with a single route
    let app = Router::new()
        .route("/", get(hello_text))
        .route("/json", get(hello_json))
        .route("/html", get(hello_html))
        .route("/form", get(render_form).post(handle_form_submit))
        ;

    println!("Serving on http://localhost:3000 ...");
    axum::Server::bind(&"127.0.0.1:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}


// `&'static str` becomes a `200 OK` with `content-type: text/plain; charset=utf-8`
async fn hello_text() -> &'static str {
    "Hello, World!"
}


// `Json` gives a content-type of `application/json` and works with any type
// that implements `serde::Serialize`
async fn hello_json() -> Json<Value> {
    Json(json!({ "domain": "www.sunzhongwei.com", "since": 1573 }))
}


// `Html` will get a `text/html` content-type
async fn hello_html() -> Html<&'static str> {
    Html("
        <h1>Hello HTML</h1>
        <p>Hello, World!</p>
    ")
}

async fn render_form() -> Html<&'static str> {
    Html(r#"
        <html>
        <head>
            <title>Form Example</title>
        </head>
        <body>
            <h1>Form Example</h1>
            <form method="post">
                <label for="field1">Field 1:</label>
                <input type="text" name="field1" id="field1"><br>

                <label for="field2">Field 2:</label>
                <input type="text" name="field2" id="field2"><br>

                <input type="submit" value="Submit">
            </form>
        </body>
        </html>
    "#)
}

#[derive(Deserialize)]
struct FormData {
    field1: String,
    field2: String,
}

async fn handle_form_submit(Form(form_data): Form<FormData>) -> Html<String> {
    let response_html = format!(
        r#"
        <html>
        <head>
            <title>Form Submission Result</title>
        </head>
        <body>
            <h1>Form Submission Result</h1>
            <p>Field 1: {}</p>
            <p>Field 2: {}</p>
        </body>
        </html>
    "#,
        form_data.field1, form_data.field2
    );

    Html(response_html)
}

为了简化,直接返回了 HTML 字符串,而没有使用正常框架内置的 HTML 模板。

可是 axum 也没有内置 HTML 模板功能,后续我将尝试三方模块库 askama, 非常类似 python jinja 的一个模板库。

编译运行

cargo run

然后在浏览器里输入

http://localhost:3000/form

即可看到 form 表单,并提交。如下图:

rust axum html form

rust axum html form

下面是遇到的一些问题,及相关知识点。

cannot find derive macro Deserialize in this scope

error: cannot find derive macro `Deserialize` in this scope
  --> src/main.rs:73:10
   |
73 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
   |
note: `Deserialize` is imported here, but it is only a trait, without a derive macro

问题出在我配置的 serde 依赖不对。有问题的 Cargo.toml 配置文件:

[dependencies]
axum = "0.6"
serde = "1.0.192"
serde_json = "1.0.108"
tokio = { version = "1.0", features = ["full"] }

其中的 serde 依赖,是我通过命令

cargo add serde

添加的。实际这是错误的,应该手动修改 Cargo.toml 文件,参考:

https://serde.rs/derive.html

正确的配置为:

serde = { version = "1.0", features = ["derive"] }

为何引入 serde 及 serde_json

在 Rust 中,标准库(std)没有提供内置的 JSON 序列化库。 可以使用第三方库 serde_json 来进行 JSON 的序列化和反序列化操作。 serde_json 是 Rust 社区中最常用的 JSON 序列化库之一, 它基于 serde 库提供了方便的 JSON 序列化和反序列化功能。

为何返回的 html 字符串前加上 r#

  • r"some string" 是 rust 的原始字符串,及不识别任何转义。可以在里面随便写反斜杠和空白字符。
  • r#"some string"# 则可以在字符串中使用双引号,而不需要转义。# 的数量可以为任意个,只要前后的 # 数量一致即可。

查看合集

📖 Rust web 框架 axum 教程:从入门到遥遥领先

参考

  • https://docs.rs/axum/latest/axum/response/index.html

tags: axum

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式