创建 应用程序实例 后,您可以开始使用事件处理程序定义应用程序逻辑。
事件处理程序是一个接收 Event
实例并返回响应的函数。您可以将其与其他框架中的控制器进行比较。
定义事件处理程序
您可以使用 defineEventHandler
或 eventHandler
实用程序定义事件处理程序:
您可以互换使用 defineEventHandler
和 eventHandler
。它们是别名。您可以使用您喜欢的那个,但坚持使用以保持一致性。
import { defineEventHandler } from 'h3'
defineEventHandler((event) => {
return 'Response'
})
回调函数可以是同步的,也可以是异步的:
defineEventHandler(async (event) => {
return 'Response'
})
对象语法
您可以在defineEventHandler
中使用对象语法来获得更多灵活的选项。
defineEventHandler({
onRequest: [],
onBeforeResponse: [],
handler: (event) => {
return 'Response'
},
})
响应类型
事件处理程序返回的值会自动转换为响应。它可以是:
- JSON 可序列化值。如果返回 JSON 对象或可序列化值,它将被字符串化并使用默认的
application/json
内容类型发送。 string
:使用默认的text/html
内容类型按原样发送。null
:h3,结束响应带有204 - 无内容
状态代码。- Web
ReadableStream
或 nodeReadable
- Web
ArrayBuffer
或 nodeBuffer
- Web Fetch Response
Error
实例。支持,但建议抛出错误,而不是使用createError
实用程序返回错误。
上述任何值都可以包装在 Promise
中。这意味着您可以从事件处理程序返回 Promise
,h3 将等待它解析后再发送响应。
示例: 发送 HTML 响应:
app.use(defineEventHandler(async event => '<h1>Hello world!</h1>'))
示例: 发送 JSON 响应:
app.use(
'/api',
defineEventHandler(async event => ({ url: event.node.req.url })),
)
示例: Send a promise:
app.use(
defineEventHandler(async (event) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ url: event.node.req.url })
}, 1000)
})
}),
)
错误处理
您可以使用 createError
实用程序轻松控制返回的错误。
import { createError, defineEventHandler } from 'h3'
app.use(
'/validate',
defineEventHandler((event) => {
throw createError({
status: 400,
statusMessage: 'Bad Request',
message: 'Invalid user input',
data: { field: 'email' }
})
}),
)
这将以400 - Bad Request
状态代码和以下 JSON 响应结束请求:
{
"status": 400,
"message": "An error occurred"
}
字符串与对象错误
使用 createError
创建错误时,您还可以选择传递字符串而不是对象。这样做将设置错误的 message
属性。在这种情况下,statusCode
将默认为 500
。
import { createError, defineEventHandler } from 'h3'
app.use(
'/hello',
defineEventHandler((event) => {
throw createError('An error occurred')
}),
)
!TIP 通常,“message”包含简短、人性化的错误描述,而“statusMessage”特定于 HTTP 响应,并描述与响应状态代码相关的状态文本。 在客户端-服务器上下文中,建议使用简短的“statusMessage”,因为它可以在客户端访问。否则,传递给服务器上“createError”的“message”将不会传播到客户端(您可以改用“data”)。考虑避免将动态用户输入放入消息中,以避免潜在的安全问题。
内部错误
如果在调用事件处理程序期间抛出带有new Error()
的错误(没有createError
),h3 将自动将其捕获为 “500 - 内部服务器错误” 状态响应,认为这是一个未处理的错误。
app.use(
'/hello',
defineEventHandler((event) => {
// 不要这样做并使用 createError()!
throw new Error('Something went wrong')
}),
)
惰性事件处理程序
您可以使用 defineLazyEventHandler
或 lazyEventHandler
实用程序定义惰性事件处理程序。这允许您定义一些一次性逻辑,这些逻辑仅在收到与路由匹配的第一个请求时执行一次。
惰性事件处理程序必须返回一个事件处理程序:
import { defineLazyEventHandler } from 'h3'
app.use(
defineLazyEventHandler(() => {
console.log('This will be executed only once')
// 这将仅执行一次
return defineEventHandler((event) => {
// 这将在每次请求时执行
return 'Response'
})
}),
)
这对于定义一些一次性逻辑(如配置、类初始化、大量计算等)很有用。
中间件
不返回任何值的事件处理程序充当中间件。它们可用于向您的应用程序添加副作用,如日志记录、缓存等,或修改请求或响应。
!TIP 中间件模式不推荐用于 h3。副作用会影响全局应用程序性能并使跟踪逻辑更加困难。 而是使用 h3 可组合项和对象语法钩子。
与普通事件处理程序类似,您可以使用 defineEventHandler
或 eventHandler
实用程序定义中间件:
defineEventHandler((event) => {
console.log(`Middleware. Path: ${event.path}`)
})
!IMPORTANT 中间件不得返回任何值或直接返回
event
的响应。 如果您返回响应,它将充当普通事件处理程序!
注册中间件
然后,您可以使用 use
方法将中间件注册到 app 实例:
app.use(
defineEventHandler((event) => {
console.log('Middleware 1')
}),
)
app.use(
defineEventHandler((event) => {
console.log('Middleware 2')
}),
)
app.use(
defineEventHandler((event) => {
return 'Response'
}),
)
您可以根据需要定义任意数量的中间件。它们将按照注册顺序被调用。
转换为 h3 处理程序
在某些情况下,您可能需要将为 Node.js 或其他框架制作的事件处理程序或实用程序转换为 h3。 有内置实用程序可以执行此操作。!
从 Node.js 处理程序转换
如果您有一个为 Node.js 制作的带有 (req, res) => {}
语法的旧式请求处理程序,则可以使用 fromNodeListener
将其转换为 h3 事件处理程序。
import { createApp, fromNodeMiddleware } from 'h3'
import exampleMiddleware from 'example-node-middleware'
export const app = createApp()
app.use(fromNodeListener(exampleMiddleware()))
!TIP 例如,这将帮助您将 Vite 中间件模式 与 h3 应用结合使用。
从 Web 处理程序转换
您可以使用 fromWebHandler
实用程序将类似 fetch 的函数(带有 Request => Response
签名)转换为 h3 事件处理程序。
import { webHandler } from 'web-handler' // 该包不存在,它只是一个例子
import { createApp, fromWebHandler } from 'h3'
export const app = createApp()
app.use(fromWebHandler(webHandler))