AWS Lambda
AWS Lambda 是亚马逊云服务提供的 Serverless 平台,你可以根据事件触发运行代码,底层计算资源由平台自动管理。
Hono 可以在 Node.js 18 及以上环境的 AWS Lambda 上运行。
1. 环境准备
在 AWS Lambda 上创建应用时,CDK 可以帮助你配置 IAM 角色、API Gateway 等功能。
使用 cdk CLI 初始化项目。
sh
mkdir my-app
cd my-app
cdk init app -l typescript
npm i hono
npm i -D esbuild
mkdir lambda
touch lambda/index.tssh
mkdir my-app
cd my-app
cdk init app -l typescript
yarn add hono
yarn add -D esbuild
mkdir lambda
touch lambda/index.tssh
mkdir my-app
cd my-app
cdk init app -l typescript
pnpm add hono
pnpm add -D esbuild
mkdir lambda
touch lambda/index.tssh
mkdir my-app
cd my-app
cdk init app -l typescript
bun add hono
bun add -D esbuild
mkdir lambda
touch lambda/index.ts2. Hello World
编辑 lambda/index.ts。
ts
import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
export const handler = handle(app)3. 部署
编辑 lib/my-app-stack.ts。
ts
import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'
import * as lambda from 'aws-cdk-lib/aws-lambda'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
export class MyAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props)
const fn = new NodejsFunction(this, 'lambda', {
entry: 'lambda/index.ts',
handler: 'handler',
runtime: lambda.Runtime.NODEJS_22_X,
})
const fnUrl = fn.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
})
new cdk.CfnOutput(this, 'lambdaUrl', {
value: fnUrl.url!,
})
}
}最后运行以下命令进行部署:
sh
cdk deploy返回二进制数据
Hono 支持返回二进制数据。在 Lambda 中,需要以 base64 编码的方式返回二进制内容。 只要将 Content-Type 设置为二进制类型,Hono 就会自动将数据编码为 base64。
ts
app.get('/binary', async (c) => {
// ...
c.status(200)
c.header('Content-Type', 'image/png') // 表示二进制数据
return c.body(buffer) // 支持 `ArrayBufferLike` 类型,将自动编码为 base64
})访问 AWS Lambda 对象
在 Hono 中,可以通过绑定 LambdaEvent、LambdaContext 类型并使用 c.env 来访问 AWS Lambda 的 Events 与 Context。
ts
import { Hono } from 'hono'
import type { LambdaEvent, LambdaContext } from 'hono/aws-lambda'
import { handle } from 'hono/aws-lambda'
type Bindings = {
event: LambdaEvent
lambdaContext: LambdaContext
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/aws-lambda-info/', (c) => {
return c.json({
isBase64Encoded: c.env.event.isBase64Encoded,
awsRequestId: c.env.lambdaContext.awsRequestId,
})
})
export const handler = handle(app)访问 RequestContext
同样可以通过绑定 LambdaEvent 类型并使用 c.env.event.requestContext 获取 AWS Lambda 的请求上下文。
ts
import { Hono } from 'hono'
import type { LambdaEvent } from 'hono/aws-lambda'
import { handle } from 'hono/aws-lambda'
type Bindings = {
event: LambdaEvent
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/custom-context/', (c) => {
const lambdaContext = c.env.event.requestContext
return c.json(lambdaContext)
})
export const handler = handle(app)v3.10.0 之前的写法(已弃用)
旧版本可以通过绑定 ApiGatewayRequestContext 类型并使用 c.env. 访问请求上下文。
ts
import { Hono } from 'hono'
import type { ApiGatewayRequestContext } from 'hono/aws-lambda'
import { handle } from 'hono/aws-lambda'
type Bindings = {
requestContext: ApiGatewayRequestContext
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/custom-context/', (c) => {
const lambdaContext = c.env.requestContext
return c.json(lambdaContext)
})
export const handler = handle(app)Lambda 响应流式传输
通过修改 AWS Lambda 的调用模式,可以实现流式响应。
diff
fn.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
+ invokeMode: lambda.InvokeMode.RESPONSE_STREAM,
})通常,你需要借助 awslambda.streamifyResponse 将数据块写入 NodeJS.WritableStream 才能实现流式响应。使用 AWS Lambda 适配器后,将 handle 替换为 streamHandle 即可按照 Hono 的方式返回流式响应。
ts
import { Hono } from 'hono'
import { streamHandle } from 'hono/aws-lambda'
import { streamText } from 'hono/streaming'
const app = new Hono()
app.get('/stream', async (c) => {
return streamText(c, async (stream) => {
for (let i = 0; i < 3; i++) {
await stream.writeln(`${i}`)
await stream.sleep(1)
}
})
})
export const handler = streamHandle(app)