NuxtN
Nuxt4mo ago
5 replies
TheBlueMeisterGamer

Proxy Websocket Messages in Nuxt 3/4

Hey there,

im have implemented a websocket server in my Fastify Backend running separatly from nuxt in a diffrent docker container on same host. I already got endpoint /api/[...].ts up running which proxies everything to backend:

import { joinURL } from 'ufo'

export default defineEventHandler(async (event) => {
  const apiUrl = useRuntimeConfig().apiUrl as string

  const target = joinURL(apiUrl, event.path)

  return proxyRequest(event, target)
})


Now i noticed that this doesnt work with websockets and even if i enable experimental websocket support in nitro. If i enable the experimental websocket support nitro will boot up and websocket but not proxy it to my backend.

I know that this is an old topic which came up multiple times in the past, however i tried to find a solution to this topic using ChatGPT and Github Copilot which suggested that i build a websocket server using defineWebSocketHandler and put that into <PROJECT_ROOT>/server/api/ws.ts (Route is currently /api/ws on both frontend and backend). However using the following code peice, i get only errors, because the websocket just reconnects without sending any messages.

I got the frontend logic in browser working which sends messages to the nitro server, but the code doesnt send it to the backend.

IMPORTANT: Im in the dev envoirment currently in Jetbrains Webstorm

In Console i get WebSocket Connectet several thousand times over a span of 5 minutes.

import WebSocket from 'ws';

export default defineWebSocketHandler({
    open(peer) {
        const backend = new WebSocket(peer.request.url);
        const queue:string[] = [];

        backend.on("open", () => {
            console.log("WebSocket opened");
            for(const msg of queue) {
                backend.send(msg);
            }
        })

        // forward backend messages → client
        backend.on('message', (data) => peer.send(data));
        peer.websocket.onmessage = (msg) => {
            if(backend.readyState !== WebSocket.OPEN) {
                queue.push(msg.data as string);
                return;
            }
            console.log("<" + msg.data);
            backend.send(msg.data);
        }

        backend.on('close', () => peer.close());
        peer.websocket.onclose = () => backend.close()
    },
});


i added the queue because when i send on the frontend, i dont know if the connection to backend is established.


Websocket service connection code:
websocket.requestUpdate(["teams", "status"]);
websocket.requestTeamsList();

websocket.on("*", (message: WebsocketMessage) => {
    if(message.type === 'error' && message.data){
        error.value = message.data.message;
    }
    else {
        useWebsocketRequestHandler(message);
    }
})

onMounted(async () => {
    // some other logic
    websocket.connect(useAuth().findAccessToken()?.token ?? '');
})


(websocket service in message below)

Nuxt info:

- Operating System: Windows_NT
- Node Version: v22.19.0
- Nuxt Version: 3.17.5
- CLI Version: 3.25.1
- Nitro Version: 2.11.12
- Package Manager: npm@10.9.3
- Builder: -
- User Config: modules, ssr, devtools, site, spaLoadingTemplate, runtimeConfig,
build
, routeRules, devServer, future, compatibilityDate,
vite
, typescript, eslint, i18n, image, pwa, security, umami
- Runtime Modules: nuxt-security@2.2.0, @nuxtjs/i18n@9.5.5, @pinia/nuxt@0.11.1, nuxt-umami@3.2.0, @galaxybotweb/components@1.0.133, @nuxt/eslint@1.4.1, @nuxt/image@1.10.0, nuxt-tiptap-editor@2.2.1, @vite-pwa/nuxt@1.0.3, @nuxtjs/robots@5.2.10
- Build Modules: -
Was this page helpful?