【问题标题】:Deno: How to use WebSocket with oak?Deno:如何将 WebSocket 与橡木一起使用?
【发布时间】:2021-02-22 06:57:48
【问题描述】:

由于上周三发布了 Deno,我尝试使用它并重做聊天应用程序的小示例,我尝试了这个:

import { Application, Router, send } from 'https://deno.land/x/oak/mod.ts';
import { listenAndServe } from 'https://deno.land/std/http/server.ts'

const app = new Application();
const router = new Router();

router
  .get('/ws', handleSocket);


app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: HTTP_PORT });

app.ts

import { WebSocket, acceptWebSocket, isWebSocketCloseEvent, acceptable } from 'https://deno.land/std/ws/mod.ts'
import { v4 } from 'https://deno.land/std/uuid/mod.ts'

const users = new Map<string, WebSocket>()

export const handleSocket = async (ctx: any) => {
  if (acceptable(ctx.request.serverRequest)) {
    const { conn, r: bufReader, w: bufWriter, headers } = ctx.request.serverRequest;
    const socket = await acceptWebSocket({
      conn,
      bufReader,
      bufWriter,
      headers,
    });

    await socketEventHandlers(socket);
  } else {
    throw new Error('Error when connecting websocket');
  }
}
...

export const socketEventHandlers = async (ws: WebSocket): Promise<void> => {
  // Register user connection
  const userId = v4.generate()

  users.set(userId, ws)
  await broadcast(`> User with the id ${userId} is connected`)

  // Wait for new messages
  for await (const event of ws) {
    const message = typeof event === 'string' ? event : ''

    await broadcast(message, userId)

    // Unregister user conection
    if (!message && isWebSocketCloseEvent(event)) {
      users.delete(userId)
      await broadcast(`> User with the id ${userId} is disconnected`)
    }
  }
}

socket.ts

websocket 连接与import { listenAndServe } from 'https://deno.land/std/http/server.ts' 完美配合,但使用上面的代码时出现WebSocket connection to 'ws://localhost:3000/ws' failed: Invalid frame header 之类的错误。

有人有解决办法吗?谢谢 ;)

【问题讨论】:

    标签: websocket deno


    【解决方案1】:

    TL;DR - 自答案被接受以来已更新,现在更简单了。

    router.get('/ws', async ctx => {
        const sock = await ctx.upgrade();
        handleSocket(sock);
    });
    

    信用https://github.com/oakserver/oak/pull/137

    【讨论】:

      【解决方案2】:

      出现此问题是因为您使用了错误版本的库。在 Deno 中始终使用版本化 URL。

      对于 Deno 1.0.0,您需要使用 oak v4.0.0std v0.51.0

      app.ts

      import { Application, Router, send } from 'https://deno.land/x/oak@v4.0.0/mod.ts';
      

      socket.ts

      import { WebSocket, acceptWebSocket, isWebSocketCloseEvent, acceptable } from 'https://deno.land/std@0.51.0/ws/mod.ts'
      import { v4 } from 'https://deno.land/std@0.51.0/uuid/mod.ts'
      

      进行这些更改后,您将能够正确连接到 WebSocket 服务器。

      const ws = new WebSocket("ws://127.0.0.1:8080/ws")
      ws.onopen = function () {
        ws.send('OAK is working!')
      }
      

      【讨论】:

        【解决方案3】:

        在解决将 http 连接升级到同一端口上的 websocket 的相同问题时,以下过于简化的解决方案适用于 Deno 1.2 和 Oak。

        /*
        running with Deno 1.2
        deno run --inspect --allow-net ./beautiful-socket.js
        */
        import { Application, Router, HttpError, send, Status } from "https://deno.land/x/oak@v6.0.1/mod.ts";
        import { createWebSocket, isWebSocketCloseEvent, acceptWebSocket, acceptable } from "https://deno.land/std@0.61.0/ws/mod.ts";
        
        const port = 8123;
        const users = new Set();
        const app = new Application({state:{users}});
        const router = new Router();
        
        function broadcastEach(user){
            user.send(this);
        }
        function broadcast(msg){
            console.log('---broadcasting--->', typeof msg, msg);
            users.forEach(broadcastEach, msg);
        }
        
        router.get('/socket', async (context, next) => {
            if( !context.isUpgradable ){
                throw new Error('bummers opening socket :(');
            }
            const socket = await context.upgrade();
            users.add(socket);
            broadcast(`hello! ${ socket.conn.rid }`);
            for await (const ev of socket) {
                if(isWebSocketCloseEvent(ev)){
                    users.delete(socket);
                    broadcast(`bye! ${ socket.conn.rid }`);
                }else{
                    broadcast(ev);
                };
            }
        });
        
        router.get('/', async (context) => {
            context.response.body = `<!doctype html>
        <html><body>
        <p>let's chat...open the console to chat it up</p>
        <script>
        console.log(123);
        const pipe = new WebSocket("ws://${context.request.url.host}/socket");
        function fire(ev){
            switch(ev.type){
            case 'message':
                switch(typeof ev.data){
                case 'string':
                    console.log('msg text', ev.data);
                break;
                case 'object':
                    ev.data.arrayBuffer().then(ab=>{ console.log(new Uint8Array(ab)); });
                break;
                }
            break;
            default:
                console.log(ev.type ,ev);
            }
        }
        function hello(msg){
            if(msg === undefined){
                msg = new ArrayBuffer(4);
                const uint = new Uint8Array(msg);
                uint[0] = 4;
                uint[1] = 3;
                uint[2] = 2;
                uint[3] = 1;
            }
            pipe.send(msg);
        }
        
        pipe.addEventListener('open', fire);
        pipe.addEventListener('close', fire);
        pipe.addEventListener('message', fire);
        pipe.addEventListener('error', fire);
        
        
        </script>
        </body></html>
        `;
        });
        
        app.use(router.routes());
        app.use(router.allowedMethods());
        
        app.addEventListener('error', (ev)=>{
            console.error(ev);
            debugger;
        });
        
        app.addEventListener('listen', (server)=>{
            console.log(`open ${ server.secure ? 'https':'http' }://${ server.hostname }:${ server.port }`);
        });
        const whenClosed = app.listen(`:${port}`);
        await whenClosed;
        console.log(`closed http :${port}, bye`);
        

        【讨论】:

          猜你喜欢
          • 2021-01-28
          • 1970-01-01
          • 1970-01-01
          • 2021-05-30
          • 2021-07-20
          • 1970-01-01
          • 2021-09-16
          • 2016-06-09
          相关资源
          最近更新 更多