Node.js
Node.js 是开源、跨平台的 JavaScript 运行时环境。
Hono 最初并非为 Node.js 设计,但通过 Node.js 适配器,也可以在 Node.js 上运行。
说明
它支持 Node.js 18.x 及以上系列。各系列的具体版本要求如下:
- 18.x => 18.14.1+
- 19.x => 19.7.0+
- 20.x => 20.0.0+
基本上,使用各主要版本系列中的最新版即可。
1. 初始化
Node.js 有可用的项目模板。 使用「create-hono」命令开始创建项目。 本示例选择 nodejs 模板。
npm create hono@latest my-appyarn create hono my-apppnpm create hono my-appbun create hono@latest my-appdeno init --npm hono my-app进入 my-app 并安装依赖。
cd my-app
npm icd my-app
yarncd my-app
pnpm icd my-app
bun i2. Hello World
编辑 src/index.ts:
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Node.js!'))
serve(app)如果想优雅地关闭服务器,可以这样编写:
const server = serve(app)
// graceful shutdown
process.on('SIGINT', () => {
server.close()
process.exit(0)
})
process.on('SIGTERM', () => {
server.close((err) => {
if (err) {
console.error(err)
process.exit(1)
}
process.exit(0)
})
})说明
在 Node.js 上,serve() 封装了 node:http 模块,并返回底层服务器实例,因此需要你自行关闭它。Bun 和 Deno 原生支持 Fetch 处理函数,并自行管理服务器,所以对应指南无需这一步。
3. 运行
在本地运行开发服务器,然后在浏览器中访问 http://localhost:3000。
npm run devyarn devpnpm dev更改端口号
可以使用 port 选项指定端口号。
serve({
fetch: app.fetch,
port: 8787,
})WebSocket
@hono/node-server 内置 WebSocket 支持。安装 ws,如果使用 TypeScript,还需要安装 @types/ws。然后创建带有 { noServer: true } 的 WebSocketServer,并通过 websocket 选项将其传给 serve()。
@hono/node-ws 已弃用。
import { serve, upgradeWebSocket } from '@hono/node-server'
import { Hono } from 'hono'
import { WebSocketServer } from 'ws'
const app = new Hono()
app.get(
'/ws',
upgradeWebSocket(() => ({
onMessage(event, ws) {
ws.send(event.data)
},
}))
)
const wss = new WebSocketServer({ noServer: true })
serve({
fetch: app.fetch,
websocket: { server: wss },
})访问原生 Node.js API
可以通过 c.env.incoming 和 c.env.outgoing 访问 Node.js API。
import { Hono } from 'hono'
import { serve, type HttpBindings } from '@hono/node-server'
// or `Http2Bindings` if you use HTTP2
type Bindings = HttpBindings & {
/* ... */
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/', (c) => {
return c.json({
remoteAddress: c.env.incoming.socket.remoteAddress,
})
})
serve(app)提供静态文件
可以使用 serveStatic 提供本地文件系统中的静态文件。例如,假设目录结构如下:
./
├── favicon.ico
├── index.ts
└── static
├── hello.txt
└── image.png如果收到 /static/* 路径的请求,并想返回 ./static 下的文件,可以这样编写:
import { serveStatic } from '@hono/node-server/serve-static'
app.use('/static/*', serveStatic({ root: './' }))注意
root 选项相对于当前工作目录(process.cwd())解析路径。这意味着行为取决于你从哪个目录启动 Node.js 进程,而非源文件所在目录。如果从其他目录启动服务器,文件路径解析可能失败。
要可靠地解析路径,始终指向源文件所在目录,请使用 import.meta.url:
import { fileURLToPath } from 'node:url'
import { serveStatic } from '@hono/node-server/serve-static'
app.use(
'/static/*',
serveStatic({ root: fileURLToPath(new URL('./', import.meta.url)) })
)使用 path 选项提供根目录中的 favicon.ico:
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))如果收到 /hello.txt 或 /image.png 路径的请求,并想返回 ./static/hello.txt 或 ./static/image.png 文件,可以使用以下方式:
app.use('*', serveStatic({ root: './static' }))rewriteRequestPath
如果要将 http://localhost:3000/static/* 映射到 ./statics,可以使用 rewriteRequestPath 选项:
app.get(
'/static/*',
serveStatic({
root: './',
rewriteRequestPath: (path) =>
path.replace(/^\/static/, '/statics'),
})
)http2
可以在 Node.js http2 服务器上运行 Hono。
未加密的 http2
import { createServer } from 'node:http2'
const server = serve({
fetch: app.fetch,
createServer,
})加密的 http2
import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'
const server = serve({
fetch: app.fetch,
createServer: createSecureServer,
serverOptions: {
key: readFileSync('localhost-privkey.pem'),
cert: readFileSync('localhost-cert.pem'),
},
})构建和部署
Dockerfile
下面是一个 Node.js Dockerfile 示例。
FROM node:22-alpine AS base
FROM base AS builder
RUN apk add --no-cache gcompat
WORKDIR /app
COPY package*json tsconfig.json src ./
RUN npm ci && \
npm run build && \
npm prune --production
FROM base AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 hono
COPY --from=builder --chown=hono:nodejs /app/node_modules /app/node_modules
COPY --from=builder --chown=hono:nodejs /app/dist /app/dist
COPY --from=builder --chown=hono:nodejs /app/package.json /app/package.json
USER hono
EXPOSE 3000
CMD ["node", "/app/dist/index.js"]