Appearance
Node.js
Node.js 是一个开源的、跨平台的 JavaScript 运行环境。
Hono 最初并不是为 Node.js 设计的,但通过一个 Node.js 适配器,它也可以在 Node.js 上运行。
🌐 Hono was not designed for Node.js at first, but with a Node.js Adapter, it can run on Node.js as well.
INFO
它适用于大于 18.x 的 Node.js 版本。具体要求的 Node.js 版本如下:
- 18.x => 18.14.1+
- 19.x => 19.7.0+
- 20.x => 20.0.0+
本质上,你可以简单地使用每个主要版本的最新版本。
🌐 Essentially, you can simply use the latest version of each major release.
1. 设置
🌐 1. Setup
Node.js 的入门模板已可用。使用 "create-hono" 命令启动你的项目。此示例选择 nodejs 模板。
🌐 A starter for Node.js is available. Start your project with "create-hono" command. Select nodejs template for this example.
sh
npm create hono@latest my-appsh
yarn create hono my-appsh
pnpm create hono my-appsh
bun create hono@latest my-appsh
deno init --npm hono my-appMove to my-app and install the dependencies.
sh
cd my-app
npm ish
cd my-app
yarnsh
cd my-app
pnpm ish
cd my-app
bun i2. 你好,世界
🌐 2. Hello World
编辑 src/index.ts:
🌐 Edit src/index.ts:
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)如果你想优雅地关闭服务器,请像这样编写:
🌐 If you want to gracefully shut down the server, write it like this:
ts
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)
})
})3. 跑
🌐 3. Run
在本地运行开发服务器。然后,在你的网页浏览器中访问 http://localhost:3000。
🌐 Run the development server locally. Then, access http://localhost:3000 in your Web browser.
sh
npm run devsh
yarn devsh
pnpm dev更改端口编号
🌐 Change port number
你可以使用 port 选项来指定端口号。
🌐 You can specify the port number with the port option.
ts
serve({
fetch: app.fetch,
port: 8787,
})WebSocket
WebSocket 支持内置于 @hono/node-server。安装 ws,如果使用 TypeScript,则安装 @types/ws。然后使用 { noServer: true } 创建一个 WebSocketServer 并将其与 websocket 选项一起传递给 serve()。
🌐 WebSocket support is built into @hono/node-server. Install ws and, if you use TypeScript, @types/ws. Then create a WebSocketServer with { noServer: true } and pass it to serve() with the websocket option.
@hono/node-ws 已被弃用。
ts
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
🌐 Access the raw Node.js APIs
你可以从 c.env.incoming 和 c.env.outgoing 访问 Node.js API。
🌐 You can access the Node.js APIs from c.env.incoming and c.env.outgoing.
ts
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)提供静态文件
🌐 Serve static files
你可以使用 serveStatic 从本地文件系统提供静态文件。例如,假设目录结构如下所示:
🌐 You can use serveStatic to serve static files from the local file system. For example, suppose the directory structure is as follows:
sh
./
├── favicon.ico
├── index.ts
└── static
├── hello.txt
└── image.png如果有对路径 /static/* 的请求,并且你想返回 ./static 下的文件,你可以写如下内容:
🌐 If a request to the path /static/* comes in and you want to return a file under ./static, you can write the following:
ts
import { serveStatic } from '@hono/node-server/serve-static'
app.use('/static/*', serveStatic({ root: './' }))WARNING
root 选项将路径解析为相对于当前工作目录(process.cwd())。这意味着行为取决于 你从哪里运行 Node.js 进程,而不是你的源文件所在的位置。如果你从不同的目录启动服务器,文件解析可能会失败。
为了可靠的路径解析,总是指向与你的源文件相同的目录,请使用 import.meta.url:
🌐 For reliable path resolution that always points to the same directory as your source file, use import.meta.url:
ts
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:
🌐 Use the path option to serve favicon.ico in the directory root:
ts
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))如果收到对路径 /hello.txt 或 /image.png 的请求,并且你想返回名为 ./static/hello.txt 或 ./static/image.png 的文件,你可以使用以下方法:
🌐 If a request to the path /hello.txt or /image.png comes in and you want to return a file named ./static/hello.txt or ./static/image.png, you can use the following:
ts
app.use('*', serveStatic({ root: './static' }))rewriteRequestPath
如果你想将 http://localhost:3000/static/* 映射到 ./statics,你可以使用 rewriteRequestPath 选项:
🌐 If you want to map http://localhost:3000/static/* to ./statics, you can use the rewriteRequestPath option:
ts
app.get(
'/static/*',
serveStatic({
root: './',
rewriteRequestPath: (path) =>
path.replace(/^\/static/, '/statics'),
})
)http2
你可以在 Node.js http2 服务器 上运行 hono。
🌐 You can run hono on a Node.js http2 Server.
未加密 http2
🌐 unencrypted http2
ts
import { createServer } from 'node:http2'
const server = serve({
fetch: app.fetch,
createServer,
})加密 http2
🌐 encrypted http2
ts
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'),
},
})构建和部署
🌐 Building & Deployment
Dockerfile
这是一个 Node.js Dockerfile 的示例。
🌐 Here is an example of a Node.js Dockerfile.
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"]