WebSocket 헬퍼
WebSocket 헬퍼는 Hono 애플리케이션에서 서버 측 WebSocket을 지원하는 헬퍼이다. 현재 Cloudflare Workers / Pages, Deno, Bun 어댑터를 사용할 수 있다.
Import
ts
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers'ts
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/deno'ts
import { Hono } from 'hono'
import { createBunWebSocket } from 'hono/bun'
import type { ServerWebSocket } from 'bun'
const { upgradeWebSocket, websocket } =
createBunWebSocket<ServerWebSocket>()
// ...
export default {
fetch: app.fetch,
websocket,
}Node.js를 사용한다면 @hono/node-ws를 활용할 수 있다.
upgradeWebSocket()
upgradeWebSocket()는 WebSocket을 처리하기 위한 핸들러를 반환한다.
ts
const app = new Hono()
app.get(
'/ws',
upgradeWebSocket((c) => {
return {
onMessage(event, ws) {
console.log(`클라이언트로부터 메시지: ${event.data}`)
ws.send('서버에서 보내는 메시지!')
},
onClose: () => {
console.log('연결 종료')
},
}
})
)사용 가능한 이벤트:
onOpen- 현재 Cloudflare Workers에서 지원하지 않는다.onMessageonCloseonError
WARNING
WebSocket 헬퍼를 사용하는 라우트에서 헤더를 수정하는 미들웨어(예: CORS 적용)를 함께 사용하면, 변경 불가능한 헤더를 수정할 수 없다는 오류가 발생할 수 있다. 이는 upgradeWebSocket()도 내부적으로 헤더를 변경하기 때문이다.
따라서 WebSocket 헬퍼와 미들웨어를 동시에 사용할 때 주의해야 한다.
RPC 모드
WebSocket 헬퍼로 정의한 핸들러는 RPC 모드를 지원한다.
ts
// server.ts
const wsApp = app.get(
'/ws',
upgradeWebSocket((c) => {
//...
})
)
export type WebSocketApp = typeof wsApp
// client.ts
const client = hc<WebSocketApp>('http://localhost:8787')
const socket = client.ws.$ws() // 클라이언트용 WebSocket 객체예제
WebSocket Helper를 사용한 예제를 참고한다.
서버와 클라이언트
ts
// server.ts
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers'
const app = new Hono().get(
'/ws',
upgradeWebSocket(() => {
return {
onMessage: (event) => {
console.log(event.data)
},
}
})
)
export default appts
// client.ts
import { hc } from 'hono/client'
import type app from './server'
const client = hc<typeof app>('http://localhost:8787')
const ws = client.ws.$ws(0)
ws.addEventListener('open', () => {
setInterval(() => {
ws.send(new Date().toString())
}, 1000)
})Bun과 JSX
tsx
import { Hono } from 'hono'
import { createBunWebSocket } from 'hono/bun'
const { upgradeWebSocket, websocket } = createBunWebSocket()
const app = new Hono()
app.get('/', (c) => {
return c.html(
<html>
<head>
<meta charset='UTF-8' />
</head>
<body>
<div id='now-time'></div>
<script
dangerouslySetInnerHTML={{
__html: `
const ws = new WebSocket('ws://localhost:3000/ws')
const $nowTime = document.getElementById('now-time')
ws.onmessage = (event) => {
$nowTime.textContent = event.data
}
`,
}}
></script>
</body>
</html>
)
})
const ws = app.get(
'/ws',
upgradeWebSocket((c) => {
let intervalId
return {
onOpen(_event, ws) {
intervalId = setInterval(() => {
ws.send(new Date().toString())
}, 200)
},
onClose() {
clearInterval(intervalId)
},
}
})
)
export default {
fetch: app.fetch,
websocket,
}