Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot clone a response to a WebSocket handshake #3250

Open
JustJoostNL opened this issue Aug 9, 2024 · 4 comments
Open

Cannot clone a response to a WebSocket handshake #3250

JustJoostNL opened this issue Aug 9, 2024 · 4 comments
Labels

Comments

@JustJoostNL
Copy link

What version of Hono are you using?

4.5.4

What runtime/platform is your app running on?

Cloudflare Workers

What steps can reproduce the bug?

import { Hono } from "hono";
import { upgradeWebSocket } from "hono/cloudflare-workers";
import { WSContext } from "hono/ws";

export const websocket = new Hono();

websocket.get(
  "/ws",
  upgradeWebSocket(() => {
    return {
      onOpen: (_ev: Event, ws: WSContext) => {
        ws.send("Hello, welcome to the websocket server");
      },
      onClose: (_ev: Event, ws: WSContext) => {
        ws.send("Goodbye!");
      },
      onError: (_ev: Event, ws: WSContext) => {
        ws.send("An error occurred");
      },
      onMessage: socketRouter,
    };
  }),
);

function socketRouter(event: any, ws: WSContext) {
  switch (event.data) {
    case "ping":
      ws.send("pong");
      break;
    case "time":
      handleTimeRequest(ws);
      break;
    default:
      ws.send("Unknown command");
      break;
  }
}

function handleTimeRequest(ws: WSContext) {
  setInterval(() => {
    ws.send(new Date().toISOString());
  }, 1000);
}

What is the expected behavior?

The websocket connects like normal.

What do you see instead?

When trying to connect to the websocket:

[ERROR] An error has been thrown: TypeError: Cannot clone a response to a WebSocket handshake.                                                                                                                                     
                                                                                                                                                                                                                                     
  A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from                                                                                                                                 
  JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all
  code and events related to the Promise's I/O context have already finished.

Additional information

No response

@yusukebe
Copy link
Member

Hi @JustJoostNL

This script works well:

import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers'
import type { WSContext } from 'hono/ws'

const app = new Hono()

app.get('/', (c) => {
  return c.html(
    <html>
      <head>
        <meta charset='UTF-8' />
      </head>
      <body>
        <div id='time'></div>
        <script
          dangerouslySetInnerHTML={{
            __html: `
        const ws = new WebSocket('ws:https://localhost:8787/ws')
        const $time = document.getElementById('time')
        ws.onmessage = (event) => {
          $time.textContent = event.data
        }
        ws.onopen = (event) => {
          ws.send('time')
        }
        `,
          }}
        ></script>
      </body>
    </html>
  )
})

app.get(
  '/ws',
  upgradeWebSocket(() => {
    return {
      onClose: (_ev, ws) => {
        ws.send('Goodbye!')
      },
      onError: (_ev, ws) => {
        ws.send('An error occurred')
      },
      onMessage: socketRouter,
    }
  })
)

function socketRouter(event: any, ws: WSContext) {
  switch (event.data) {
    case 'ping':
      ws.send('pong')
      break
    case 'time':
      handleTimeRequest(ws)
      break
    default:
      ws.send('Unknown command')
      break
  }
}

function handleTimeRequest(ws: WSContext) {
  setInterval(() => {
    ws.send(new Date().toISOString())
  }, 1000)
}

export default app

@JustJoostNL
Copy link
Author

Thanks! I'll try that. Is there a reason that HTML is required? I think remember it working before without.

@yusukebe
Copy link
Member

@JustJoostNL

Is there a reason that HTML is required? I think remember it working before without.

Where do you run a WebSockets client? In my case, I wrote the HTML and created the client on it.

@JustJoostNL
Copy link
Author

I've just tried your suggestion, but unfortunately, I'm still experiencing the exact same error as before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants