스트리밍 헬퍼
스트리밍 헬퍼는 응답을 스트리밍하는 메서드를 제공한다.
임포트
ts
import { Hono } from 'hono'
import { stream, streamText, streamSSE } from 'hono/streaming'stream()
Response 객체로 간단한 스트리밍 응답을 반환한다.
ts
app.get('/stream', (c) => {
return stream(c, async (stream) => {
// 중단 시 실행할 프로세스를 작성한다.
stream.onAbort(() => {
console.log('Aborted!')
})
// Uint8Array를 작성한다.
await stream.write(new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]))
// 읽기 가능한 스트림을 파이프한다.
await stream.pipe(anotherReadableStream)
})
})streamText()
이 함수는 Content-Type:text/plain, Transfer-Encoding:chunked, 그리고 X-Content-Type-Options:nosniff 헤더를 포함한 스트리밍 응답을 반환한다.
ts
app.get('/streamText', (c) => {
return streamText(c, async (stream) => {
// 새로운 줄('\n')과 함께 텍스트를 작성한다.
await stream.writeln('Hello')
// 1초 동안 대기한다.
await stream.sleep(1000)
// 새로운 줄 없이 텍스트를 작성한다.
await stream.write(`Hono!`)
})
})WARNING
Cloudflare Workers용 애플리케이션을 개발 중이라면, Wrangler에서 스트리밍이 제대로 작동하지 않을 수 있다. 그럴 경우 Content-Encoding 헤더에 Identity를 추가한다.
ts
app.get('/streamText', (c) => {
c.header('Content-Encoding', 'Identity')
return streamText(c, async (stream) => {
// ...
})
})streamSSE()
이 함수는 Server-Sent Events(SSE)를 원활하게 스트리밍할 수 있게 해준다.
ts
const app = new Hono()
let id = 0
app.get('/sse', async (c) => {
return streamSSE(c, async (stream) => {
while (true) {
const message = `It is ${new Date().toISOString()}`
await stream.writeSSE({
data: message,
event: 'time-update',
id: String(id++),
})
await stream.sleep(1000)
}
})
})에러 처리
스트리밍 헬퍼의 세 번째 인자는 에러 핸들러다. 이 인자는 선택 사항이며, 지정하지 않으면 에러가 콘솔 에러로 출력된다.
ts
app.get('/stream', (c) => {
return stream(
c,
async (stream) => {
// 중단 시 실행할 프로세스를 작성한다.
stream.onAbort(() => {
console.log('Aborted!')
})
// Uint8Array를 작성한다.
await stream.write(
new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f])
)
// 읽기 가능한 스트림을 파이프한다.
await stream.pipe(anotherReadableStream)
},
(err, stream) => {
stream.writeln('An error occurred!')
console.error(err)
}
)
})콜백이 실행된 후 스트림은 자동으로 닫힌다.
WARNING
스트리밍 헬퍼의 콜백 함수에서 에러가 발생하면 Hono의 onError 이벤트가 트리거되지 않는다.
onError는 응답이 전송되기 전에 에러를 처리하고 응답을 덮어쓰는 훅이다. 그러나 콜백 함수가 실행될 때는 이미 스트림이 시작된 상태이므로 덮어쓸 수 없다.