Skip to content

环境变量管理:c.env 如何从 Deno/Workers 获取配置?

Deno.env.get()process.env、binding 的兼容层

在 Hono 中,c.env 是访问环境变量和平台绑定资源(如 KV、D1、R2)的统一接口。它的强大之处在于:无论你运行在 Node.js、Deno 还是 Cloudflare Workers,c.env 都提供一致的 API。这背后是 Hono 对不同运行时环境变量机制的抽象与兼容。

一、不同运行时的环境变量机制

运行时环境变量读取方式平台绑定资源
Node.jsprocess.env.MY_VAR无(需通过库集成)
DenoDeno.env.get("MY_VAR")Deno.kv, Deno.openKv()
Cloudflare Workers不支持 process.env通过 binding(如 env.MY_KV

Hono 的 c.env 统一了这些差异,让你无需关心底层实现。

二、c.env 的工作原理:Hono 的“兼容层”

当你在 Hono 中使用 c.env.MY_VARc.env.MY_KV 时,Hono 会根据运行时自动从正确的来源读取:

ts
app.get('/config', (c) => {
  const apiKey = c.env.API_KEY      // 环境变量
  const db = c.env.DB               // D1 数据库(Workers)
  const kv = c.env.MY_KV            // KV Namespace(Workers)
  const bucket = c.env.ASSETS       // R2 Bucket
  return c.json({ apiKey: 'masked' })
})
Hono 内部如何映射?
c.env.X 查找顺序Node.jsDenoCloudflare Workers
c.env.API_KEYprocess.env.API_KEYDeno.env.get("API_KEY")env.API_KEY (binding)
c.env.DBenv.DB (需手动注入)env.DB (需手动注入)env.DB (binding)

关键点c.env 是 Hono 将运行时原生环境变量和绑定资源注入到请求上下文的结果。

三、各平台具体实现

1. Cloudflare Workers(最典型)

在 Workers 中,envfetch 事件的第二个参数:

ts
// worker.ts
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    // env 包含所有定义的 binding
    const app = new Hono<{ Bindings: Env }>()
    return app.fetch(request, env, ctx) // ← env 被传入,成为 c.env
  }
}

wrangler.toml 配置 binding:

toml
[vars]
API_KEY = "your-secret-key"

[[r2_buckets]]
binding = "ASSETS"
bucket_name = "my-assets"

[[d1_databases]]
binding = "DB"
database_name = "my_db"
database_id = "..."

此时 c.env.API_KEYc.env.ASSETSc.env.DB 均可直接使用。


2. Deno

Deno 使用 Deno.env 和模块化权限:

ts
// deno.ts
const app = new Hono()

app.get('/secret', (c) => {
  const key = c.env.API_KEY // ← 映射到 Deno.env.get("API_KEY")
  return c.text(key || 'not set')
})

// 手动启动服务,注入 env
Deno.serve({
  port: 8080,
}, (req) => {
  const env = {
    API_KEY: Deno.env.get("API_KEY"), // 手动读取
    DB:'' // ... 注入 Deno KV 或其他
  }
  return app.fetch(req, env)
})

Hono 在 Deno 中通过 Deno.env.get() 读取环境变量,并依赖开发者将平台资源(如 Deno.kv)注入 env 对象。

3. Node.js

Node.js 使用 process.env

ts
// node.ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/config', (c) => {
  const port = c.env.PORT || '3000' // ← process.env.PORT
  return c.text(`Running on port ${port}`)
})

// 启动时,env 默认为 process.env
app.fire() // 或使用 server.listen()

你也可以手动注入:

ts
app.fetch(request, {
  ...process.env,
  DB: databaseClient,
  REDIS: redisClient
})

四、Hono 的“兼容层”是如何工作的?

Hono 在 app.fetch(request, env, ...) 调用时,会:

  1. 接收 env 参数(来自运行时);
  2. 创建 Context 实例;
  3. env 挂载到 c.env
  4. c.env 上实现 get 拦截(如需要)以兼容不同行为。

这使得 c.env 成为一个运行时无关的统一接口

五、最佳实践:类型安全的 c.env

定义 Bindings 类型,避免 any

ts
// types.ts
type Env = {
  API_KEY: string
  DB: D1Database
  ASSETS: R2Bucket
  MY_KV: KVNamespace
  REDIS_URL: string
}

const app = new Hono<{ Bindings: Env }>()

app.get('/profile', async (c) => {
  const user = await c.env.DB.prepare('SELECT * FROM users WHERE id = ?')
    .bind(c.req.param('id'))
    .first()
  
  const cacheKey = `user:${user.id}`
  await c.env.MY_KV.put(cacheKey, JSON.stringify(user), { expirationTtl: 3600 })

  return c.json(user)
})
  • c.env.DB 类型为 D1Database,有完整方法提示;
  • c.env.MY_KV 类型为 KVNamespace,避免拼写错误。

六、总结

机制Node.jsDenoCloudflare Workers
环境变量来源process.envDeno.env.get()env binding
平台资源手动注入手动注入env binding
c.env 行为代理 process.env代理 Deno.env + 注入资源直接使用 env

c.env 是 Hono 的“环境抽象层”,它:

  • 统一了不同平台的环境变量和绑定资源访问方式;
  • 提供了类型安全的接口;
  • 让你的代码可以在 Node.js、Deno、Workers 之间迁移而无需修改 c.env 用法。

掌握 c.env 的工作机制,你就能更自信地构建跨平台、可移植的 Hono 应用。