Deno Deploy + Hono:全栈 Deno 应用的部署范式
KV 存储、PostgreSQL、Cron Jobs 集成
Deno Deploy 是一个基于 Deno 运行时的全球边缘部署平台,以其低延迟、高安全性、无缝 TypeScript 支持和原生集成能力而著称。结合轻量、高性能的 Web 框架 Hono,你可以构建并部署一个完整的全栈 Deno 应用,无需离开 Deno 生态。
本文将展示如何使用 Deno Deploy + Hono 构建一个全栈应用,并集成:
- Deno KV(键值存储)
- PostgreSQL(关系型数据库)
- Cron Jobs(定时任务)
- 静态文件服务
- 环境变量与 Secrets
一、为什么选择 Deno Deploy + Hono?
| 特性 | 优势 |
|---|---|
| 全球边缘部署 | 请求在离用户最近的节点处理 |
| 原生 TypeScript | 无需构建,直接部署 .ts 文件 |
| 默认安全 | 默认无文件系统、网络、环境访问 |
| Hono 轻量高效 | ~2KB,路由极快,适合边缘 |
| 无缝集成 Deno 服务 | KV、PostgreSQL、Cron、R2 等 |
| 一键部署 | deployctl 或 GitHub 集成 |
适用场景:API 服务、Serverless 函数、边缘计算、全栈 Web 应用。
二、项目结构
my-deno-app/
├── src/
│ ├── routes/
│ │ ├── api.ts # Hono 路由
│ │ └── kv.ts # KV 操作
│ ├── cron/
│ │ └── cleanup.ts # 定时任务
│ ├── views/
│ │ └── index.html # 静态页面
│ └── deps.ts # 依赖导出
├── .env # 环境变量(本地)
└── project.json # Deno Deploy 配置三、初始化项目
bash
# 安装 deployctl
deno install --fresh --no-check -r -n deployctl https://deno.land/x/deploy/deployctl.ts
# 创建项目
mkdir my-deno-app && cd my-deno-app
touch src/deps.ts src/routes/api.ts project.json四、核心依赖(src/deps.ts)
ts
// src/deps.ts
export {
Hono,
cors,
serveStatic,
} from "https://deno.land/x/hono@v4.5.5/mod.ts";
export { serve } from "https://deno.land/std@0.214.0/http/server.ts";
export { Pool } from "https://deno.land/x/postgres@v0.17.0/mod.ts";
export * as dotenv from "https://deno.land/x/dotenv@v3.4.0/mod.ts";五、Hono 路由与 KV 集成
ts
// src/routes/api.ts
import { Hono } from "../deps.ts";
const app = new Hono();
// 获取 Deno KV 实例
const kv = await Deno.openKv();
// GET /api/counter - 读取计数
app.get("/api/counter", async (c) => {
const res = await kv.get(["counter"]);
const count = res.value || 0;
return c.json({ count });
});
// POST /api/counter - 增加计数
app.post("/api/counter", async (c) => {
const res = await kv.get(["counter"]);
const count = (res.value as number || 0) + 1;
await kv.set(["counter"], count);
return c.json({ count });
});
// 其他 API...
app.get("/api/hello", (c) => c.json({ msg: "Hello from Deno Deploy!" }));
export default app;Deno.openKv() 是 Deno Deploy 原生支持的全局 KV 存储,持久化、低延迟、全球同步。
六、PostgreSQL 集成
ts
// src/routes/db.ts
import { Pool } from "../deps.ts";
// 从环境变量获取数据库连接信息
const DATABASE_URL = Deno.env.get("DATABASE_URL")!;
const pool = new Pool(DATABASE_URL, 5); // 连接池大小
app.get("/api/users", async (c) => {
const client = await pool.connect();
try {
const result = await client.queryObject("SELECT id, name, email FROM users");
return c.json(result.rows);
} finally {
client.release();
}
});
app.post("/api/users", async (c) => {
const { name, email } = await c.req.json();
const client = await pool.connect();
try {
const result = await client.queryObject(
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email",
name,
email
);
return c.json(result.rows[0], 201);
} finally {
client.release();
}
});数据库连接字符串应通过 Secrets 注入:
bash
deployctl secrets set DATABASE_URL="postgres://user:pass@host:5432/db"七、Cron Jobs:定时任务
Deno Deploy 支持通过 project.json 配置定时任务。
ts
// src/cron/cleanup.ts
export default async function () {
const kv = await Deno.openKv();
// 清理 7 天前的临时数据
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000;
const entries = kv.list({ prefix: ["temp"] });
for await (const entry of entries) {
if (entry.value && entry.value.timestamp < cutoff) {
await kv.delete(entry.key);
console.log("Cleaned:", entry.key);
}
}
}配置 project.json
json
{
"name": "my-deno-app",
"main": "src/main.ts",
"include": [
"src/"
],
"exclude": [
"src/cron/"
],
"cron": [
{
"name": "cleanup-temp-data",
"schedule": "0 2 * * *",
"path": "/cron/cleanup"
}
],
"envVars": {
"LOG_LEVEL": "info"
},
"permissions": {
"kvRead": true,
"kvWrite": true,
"unstable": true
}
}Cron 函数通过 path 指向模块,Deno Deploy 会自动调用其默认导出。
八、主应用入口(src/main.ts)
ts
// src/main.ts
import { Hono } from "./deps.ts";
import apiRouter from "./routes/api.ts";
import { serveStatic } from "hono/deno-runtime";
import { cors } from "hono/cors";
const app = new Hono();
// CORS
app.use("*", cors());
// API 路由
app.route("/api", apiRouter);
// 静态文件服务
app.use("/static/*", serveStatic({ root: "./" }));
app.get("/", (c) => c.html("<h1>Welcome to Deno + Hono</h1><button onclick=\"inc()\">Count: <span id='c'>0</span></button><script>async function inc(){let r=await fetch('/api/counter',{method:'POST'});let j=await r.json();document.getElementById('c').textContent=j.count}</script>"));
// 404
app.notFound((c) => c.text("Not Found", 404));
// 错误处理
app.onError((err, c) => {
console.error(err);
return c.json({ error: "Internal Server Error" }, 500);
});
// 启动服务器(Deno Deploy 自动处理)
// 无需 `serve()`,Deno Deploy 会自动运行
export default app;九、环境变量与 Secrets
1. 本地开发(.env)
plaintext
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
LOG_LEVEL=debug2. 部署时设置 Secrets
bash
# 设置数据库连接
deployctl secrets set DATABASE_URL="your-real-db-url"
# 设置 JWT 密钥
deployctl secrets set JWT_SECRET="your-super-secret"3. 在代码中使用
ts
const dbUrl = Deno.env.get("DATABASE_URL");
if (!dbUrl) throw new Error("DATABASE_URL not set");十、部署到 Deno Deploy
bash
# 登录
deployctl login
# 部署(开发环境)
deployctl deploy --project=my-deno-app src/main.ts
# 部署生产环境
deployctl deploy --project=my-deno-app --prod src/main.ts应用将部署到 https://my-deno-app.deno.dev
十一、最佳实践
| 实践 | 说明 |
|---|---|
使用 Hono 而非 std/http | 更丰富的路由、中间件生态 |
| 优先使用 Deno KV | 低延迟,适合会话、缓存 |
| 连接池管理 PostgreSQL | 避免连接耗尽 |
| Cron 任务轻量 | 执行时间建议 < 60s |
| Secrets 管理敏感信息 | 不要硬编码 |
使用 unstable 权限时谨慎 | 如 WebSocket、KV |
十二、总结
| 能力 | Deno Deploy + Hono 实现 |
|---|---|
| 全球边缘部署 | Deno Deploy 自动分发 |
| TypeScript 原生 | 无需构建,直接运行 |
| KV 存储 | Deno.openKv() 全局可用 |
| PostgreSQL | 通过 postgres 模块连接 |
| Cron Jobs | project.json 配置定时任务 |
| 安全隔离 | 默认权限控制 |
| 快速部署 | deployctl 一键发布 |
Deno Deploy + Hono = 全栈 Deno 应用的黄金组合。
你可以在一个统一的 TypeScript 环境中,构建从 API、数据库到定时任务的完整应用,无需切换技术栈,无需复杂配置。
立即尝试构建你的下一个全栈应用,体验 Deno 生态的简洁与强大!