Skip to content

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=debug
2. 部署时设置 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 Jobsproject.json 配置定时任务
安全隔离默认权限控制
快速部署deployctl 一键发布

Deno Deploy + Hono = 全栈 Deno 应用的黄金组合
你可以在一个统一的 TypeScript 环境中,构建从 API、数据库到定时任务的完整应用,无需切换技术栈,无需复杂配置

立即尝试构建你的下一个全栈应用,体验 Deno 生态的简洁与强大!