WebSocket サーバーに接続する

Recipe ID: net-009

チャットアプリやリアルタイム通知など、サーバーとの双方向通信(リアルタイム通信)を実現するための WebSocket 接続方法を解説します。
Tauri では @tauri-apps/plugin-websocket を使用することで、Rust バックエンドを経由した WebSocket 通信が可能になります。これにより、ブラウザの標準 WebSocket API では設定できないカスタムヘッダーの送信などが可能になります。

前提条件

この機能を使用するには、@tauri-apps/plugin-websocket プラグインが必要です。

1. プラグインのインストール

npm run tauri add websocket

2. Permissions (権限) の設定

src-tauri/capabilities/default.jsonwebsocket:default 権限を追加します。
Tauri v2 ではセキュリティの観点から allow: [{ "url": "*" }] のような無制限なワイルドカード指定は許可されていない場合があるため、接続する WebSocket サーバーの URL を明示的に指定する必要があります。

以下の例では、コード例で使用する localhost:8080echo.websocket.org などを許可しています。

{
  "permissions": [
    "websocket:default",
    {
        "identifier": "websocket:allow-connect",
        "allow": [
            { "url": "ws://localhost:8080" },
            { "url": "wss://echo.websocket.org" },
            { "url": "wss://secure-api.example.com/*" }
        ]
    }
  ]
}
注意: 本番ビルドでは実際に使用するドメインのみを許可することが強く推奨されます。

使用方法

Web 標準の new WebSocket() とは異なり、非同期の connect メソッドを使用してインスタンスを生成します。
また、イベントリスナーの登録方法も addListener を使用する形式になります。

import WebSocket from '@tauri-apps/plugin-websocket';

// 接続(Promiseを返す)
const ws = await WebSocket.connect('wss://echo.websocket.org');

// メッセージ受信
ws.addListener((msg) => {
    console.log('Received Message:', msg);
});

// メッセージ送信
await ws.send('Hello Tauri!');

// 切断
await ws.disconnect();

コード例

例1: 接続、送信、受信の基本フロー

テキストデータの送受信を行う基本的な実装です。

import WebSocket from '@tauri-apps/plugin-websocket';

async function startChat(): Promise<void> {
    try {
        const ws = await WebSocket.connect('ws://localhost:8080');

        // 接続成功時のコールバック(プラグインの仕様により別途実装が必要な場合もありますが、connect完了時点で接続済みです)
        console.log('Connected to WebSocket server');

        // メッセージ受信リスナー
        await ws.addListener((msg) => {
            // msg.type で 'Text' か 'Binary' か判別できる場合があります
            // msg.data に内容が含まれます
            console.log('Received:', msg);
        });

        // データ送信(文字列)
        await ws.send('Hello from Tauri App');
        
        // バイナリ送信も可能
        // await ws.send([0, 1, 2, 3]);

    } catch (err) {
        console.error('WebSocket connection failed:', err);
    }
}

例2: カスタムヘッダーを使用した接続

認証トークンなどをヘッダーに含めて接続する場合の例です。これはブラウザ標準の WebSocket API では不可能な機能であり、Tauri プラグインを使う大きなメリットの一つです。

import WebSocket from '@tauri-apps/plugin-websocket';

async function connectWithAuth(token: string): Promise<void> {
    try {
        const ws = await WebSocket.connect('wss://secure-api.example.com/stream', {
            headers: {
                'Authorization': `Bearer ${token}`,
                'X-App-Version': '1.0.0'
            }
        });
        
        console.log('Secure connection established');
        
        ws.addListener((msg) => {
            console.log('Secure message:', msg);
        });
        
    } catch (e) {
        console.error('Auth connection failed', e);
    }
}

注意点

* API の違い: プラグインが提供する API は標準の WebSocket オブジェクトと完全な互換性はありません(onmessage プロパティではなく addListener を使う、接続が非同期である、など)。既存の Web アプリを移植する場合はラッパーを作成するか、コードの修正が必要です。
* WSS (Secure WebSocket): 本番環境では暗号化された wss:// プロトコルの使用を強く推奨します。開発環境で ws:// を使う場合は tauri.conf.json の CSP設定などが通信をブロックしないように注意してください。