8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DenoのWebSocketサーバーの書き方 2022冬編

Posted at

DenoのWebSocketサーバーの書き方の方法をまとめます。

2022年10月現在、WebSocketサーバーの書き方としてメジャーなものは以下の2つです。

  • 標準ライブラリを使用する方法
  • oakやhonoなどのミドルウェアを使う方法

この記事ではそれぞれ使い方をまとめたいと思います。

標準ライブラリのwsモジュールは廃止されました。

標準ライブラリを使う場合

かつては標準ライブラリのwsモジュールを使うやり方が主流だったのですが、現在はこれは廃止され、httpモジュールとDeno.upgradeWebSocket()という関数を使う書き方が推奨されています。

この書き方の特徴は、サードパーティ製のライブラリは必要なく完全にDenoの組み込みAPIだけで書けるという点です。

標準ライブラリを使ってWebSocketサーバーを作成するには、以下のようなコードになります。

import { serve } from "https://deno.land/std@0.156.0/http/server.ts";
serve((req) => {
  // `Deno.upgradeWebSocket(req)`でHTTP接続をWebSocket用に切り替え
  const { response, socket } = Deno.upgradeWebSocket(req);

  // ↓socketという変数に対してaddEventListenerなどを設定し、WebScoketをハンドリング
  socket.addEventListener("message", (event) => console.log(event.data));

  // レスポンスを返してWebSocket通信スタート
  return response;
});

コード中の変数socketの中にはWebSocketを処理する変数が入っています。例えば

// 接続を開いた時の処理
socket.addEventListener("open", () => console.log("open!"));
// メッセージを受信した時の処理
socket.addEventListener("message", () => console.log("message!"));
// エラー発生時の処理
socket.addEventListener("error", () => console.log("error!"));
// 接続を閉じた時の処理
socket.addEventListener("close", () => console.log("close!"));
// メッセージを送信する
socket.send("message");
// 接続を閉じる
socket.close();

という風に書くことができます。勘が言い方はもうお分かりだと思いますが、ブラウザでnew WebSocket()した時と同じように使うことができます。

WebSocket以外もハンドリングする方法

一般的なサーバーではWebSocket以外のリクエストも捌く必要があると思います。
その場合は以下のように、url.protocolurl.pathnameを見てif文で条件分岐させます。

import { serve } from "https://deno.land/std@0.156.0/http/server.ts";

serve((req) => {
  const url = new URL(req.url);

  // if (url.pathname==="/foo") {...などで更に条件分岐させることもできる
  if (url.protocol === "wss:" || url.protocol === "ws:") {
    // websocketのハンドリング
    const { response, socket } = Deno.upgradeWebSocket(req);
    socket.addEventListener("message", (event) => console.log(event.data));
    return response;
  } else {
    // websocket以外のハンドリング
    return new Response("ok!");
  }
});

oakを使う場合

oakはexpressライクなDeno向けミドルウェアです。現時点(2022年)では一番普及しており、安定して使うことができます。

oakの場合は、ctx.upgrade()というメソッドを呼ぶことでWebSocket通信をすることができます。

import { Application, Router } from "https://deno.land/x/oak@v11.1.0/mod.ts";
const app = new Application();
const router = new Router();
router.get("/socket", (ctx) => {
  const socket = ctx.upgrade(); // ここでwebsocket接続を開始
  // ここでwebsocketのハンドリング
  socket.addEventListener("message", (e) => console.log(e.data));
});
app.use(router.routes());
app.use(router.allowedMethods());

app.listen({ port: 8080 });

Honoを使う場合

Honoもexpressのようなミドルウェアですが、他のミドルウェアより高速らしいです。Deno以外のCloudflare WorkersやBunといったランタイムでも動作することが特徴です。

HonoはWeb標準のResponse/Requestを使用しているため、Deno.upgradeWebSocket()を使ってWebSocket通信するのがよさそうです。

import { serve } from "https://deno.land/std@0.158.0/http/server.ts";
import { Hono } from "https://deno.land/x/hono@v2.2.2/mod.ts";

const app = new Hono();

app.get("/", (c) => c.text("Hello! Hono!"));
app.get("/ws/", (c) => {
  const { response, socket } = Deno.upgradeWebSocket(c.req);

  // websocketのハンドリング
  socket.addEventListener("message", (e) => console.log(e));

  return response;
});

serve(app.fetch);

まとめ

  • 標準ライブラリやHonoなど、Web標準Request/Responseを使用するサーバーにおいては、Deno.upgradeWebSocket()を使用します。
  • oakなどの、ライブラリ固有の方法が用意されている場合はそちらを使用します。

WebSocketを使おうとしたときにDeno.upgradeWebSocketがなかなか検索に引っかからず使い方が分からないという場面もありそうなので、今回まとめてみました。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?