本教程将教你如何使用 workers-rs ↗ 直接从 Rust 读写 KV。
所有教程都假设你已经完成了快速入门指南,该指南帮助你设置 Cloudflare Workers 账户、C3 ↗ 和 Wrangler。
要完成本教程,你需要:
cargo install cargo-generate打开终端窗口,运行以下命令生成 Rust Worker 项目模板:
cargo generate cloudflare/workers-rs然后选择 template/hello-world-http 模板,为项目取一个描述性名称并按 Enter。新项目位于当前目录。在编辑器中打开项目并运行 npx wrangler dev 以编译并运行项目。
在本教程中,你将使用 Rust 中的 Workers KV 构建一个应用,按给定国家名称存储和检索城市。
在终端中使用 Wrangler 为 cities 创建 KV 命名空间。这将生成需添加到项目的配置:
npx wrangler kv namespace create cities要将此配置添加到项目,打开 Wrangler 配置文件,在 build 命令上方创建 kv_namespaces 条目:
{
"kv_namespaces": [
{
"binding": "cities",
"id": "e29b263ab50e42ce9b637fa8370175e8"
}
]
}[[kv_namespaces]]
binding = "cities"
id = "e29b263ab50e42ce9b637fa8370175e8"配置完成后,你可以从 Rust 通过绑定 "cities" 访问 KV 命名空间。
对于此应用,你将创建两个路由:POST 路由接收并存储城市到 KV,GET 路由检索给定国家的城市。例如,向 /France 发送正文为 {"city": "Paris"} 的 POST 请求,应在 KV 中创建法国城市 Paris 的条目。向 /France 发送 GET 请求应从 KV 检索并返回 Paris。
安装 Serde ↗ 作为项目依赖以处理 JSON:cargo add serde。然后在 src/lib.rs 中创建应用路由器和 Country 结构体:
use serde::{Deserialize, Serialize};
use worker::*;
#[event(fetch)]
async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
let router = Router::new();
#[derive(Serialize, Deserialize, Debug)]
struct Country {
city: String,
}
router
// TODO:
.post_async("/:country", |_, _| async move { Response::empty() })
// TODO:
.get_async("/:country", |_, _| async move { Response::empty() })
.run(req, env)
.await
}对于 POST 处理程序,你从路径获取国家名称,从请求正文获取城市名称。然后以国家为键、城市为值保存到 KV。最后,应用以城市名称响应:
.post_async("/:country", |mut req, ctx| async move {
let country = ctx.param("country").unwrap();
let city = match req.json::<Country>().await {
Ok(c) => c.city,
Err(_) => String::from(""),
};
if city.is_empty() {
return Response::error("Bad Request", 400);
};
return match ctx.kv("cities")?.put(country, &city)?.execute().await {
Ok(_) => Response::ok(city),
Err(_) => Response::error("Bad Request", 400),
};
})保存文件并向此端点发送 POST 请求进行测试:
curl --json '{"city": "Paris"}' http://localhost:8787/France要检索存储在 KV 中的城市,编写一个 GET 路由,从路径获取国家名称并查询 KV。若未找到国家,还需要错误处理:
.get_async("/:country", |_req, ctx| async move {
if let Some(country) = ctx.param("country") {
return match ctx.kv("cities")?.get(country).text().await? {
Some(city) => Response::ok(city),
None => Response::error("Country not found", 404),
};
}
Response::error("Bad Request", 400)
})保存并使用 curl 请求测试端点:
curl http://localhost:8787/France完整应用的源代码应包含以下内容:
use serde::{Deserialize, Serialize};
use worker::*;
#[event(fetch)]
async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
let router = Router::new();
#[derive(Serialize, Deserialize, Debug)]
struct Country {
city: String,
}
router
.post_async("/:country", |mut req, ctx| async move {
let country = ctx.param("country").unwrap();
let city = match req.json::<Country>().await {
Ok(c) => c.city,
Err(_) => String::from(""),
};
if city.is_empty() {
return Response::error("Bad Request", 400);
};
return match ctx.kv("cities")?.put(country, &city)?.execute().await {
Ok(_) => Response::ok(city),
Err(_) => Response::error("Bad Request", 400),
};
})
.get_async("/:country", |_req, ctx| async move {
if let Some(country) = ctx.param("country") {
return match ctx.kv("cities")?.get(country).text().await? {
Some(city) => Response::ok(city),
None => Response::error("Country not found", 404),
};
}
Response::error("Bad Request", 400)
})
.run(req, env)
.await
}要部署 Worker,运行以下命令:
npx wrangler deploy