エンジニアを目指す日常ブログ

日々勉強したことのメモ。独学ですので間違っていたらコメント等で教えてください。

画面サーバ(React)とWebサーバ(Node.js)をSocket.ioで接続する方法メモ

はじめに

今回の記事の目的

画面サーバ(React)とWebサーバ(Node.js)を別々に構築して、クライアントとWebサーバ間をSocket.ioで接続する。

チャットアプリを作る事前準備になる。

参考記事

  • 画面側をReactではなくindex.htmlで作成している記事。Reactで作る場合もこちらがベースとなる。 qiita.com
  • 公式ドキュメントでチャットアプリを作成するチュートリアル

Get started | Socket.IO

  • 公式ドキュメントのクライアントサイドの設定方法。Reactでのやり方は載っていない。

Client Initialization | Socket.IO

前提

環境は以下の記事の通り、Webサーバ用コンテナと画面サーバ用コンテナを用意し、各サーバを立てている状況。

tomiko0404.hatenablog.com

おそらくこんなイメージ。(間違っていたら修正します)

イメージ
イメージ

Webサーバ側の設定

socket.ioのインストール

socket.ioをインストールする。

$ yarn add socket.io

index.jsの変更

Webサーバ側のindex.jsは以下の記載とする。

index.js

// 基本設定
const express = require("express");
const portNumber = 3000;
const app = express(); // Expressを利用したサーバ作成
const server = require("http").createServer(app); // Expressを用いないserverも必要なので作成

// 別オリジンからのアクセスを許可する(CORSモジュール利用)
const cors = require("cors");
app.use(cors());

// HTTPアクセス時の応答を定義
app.get("/", (req, res) => {
    res.status(200).send("OK!");
});

// サーバーオブジェクトsocketioを作成する
const { Server } = require("socket.io");
const io = new Server(server, {
    cors: {                      // corsモジュールでは上手くCORSできないため、Server作成時の引数にオプションを追加する
        origin: "*",
        methods: ["GET", "POST"],
    },
});

// ブラウザから接続されたときの処理を定義する
io.on("connection", (socket) => { // ブラウザから接続されたときの処理
    console.log("a user connected");
    socket.on("disconnect", () => { // ブラウザが切断したときの処理
        console.log("user disconnected");
    });
});

// serverをPORT3000で待ち受ける。
// ※app.listenだとNG。
server.listen(portNumber);
console.log(`Web server is on. PortNumber is ${portNumber}.`);

解説

基本設定

以下の部分は、基本設定になるため過去の記事を参照。Expressサーバのappと、createServerで作ったserverの2つがあることに注意。listenする際はcreateServerで作ったserverを利用している。

// 基本設定
const express = require("express");
const portNumber = 3000;
const app = express(); // Expressを利用したサーバ作成
const server = require("http").createServer(app); // Expressを用いないserverも必要なので作成

// 別オリジンからのアクセスを許可する(CORSモジュール利用)
const cors = require("cors");
app.use(cors());

// HTTPアクセス時の応答を定義
app.get("/", (req, res) => {
    res.status(200).send("OK!");
});

// serverをPORT3000で待ち受ける。
// ※app.listenだとNG。
server.listen(portNumber);
console.log(`Web server is on. PortNumber is ${portNumber}.`);

過去の記事
WEBサーバと画面サーバを作成して相互に通信させる - エンジニアを目指す日常ブログ
Node.js + Express でWEB-APIサーバを作成する - エンジニアを目指す日常ブログ

クライアントとの接続

Socket.ioサーバの作成は以下の記載で実施する。

const { Server } = require("socket.io");
const io = new Server(server)

公式ドキュメント socket.io

CORSについて

CORSについては、corsモジュールを利用すれば問題ないかと思ったが、これでは接続できなかった。

そのため以下のドキュメントに従って設定を行なった。 socket.io

// const io = new Server(server)を書き換え
const io = new Server(server, {
    cors: {                      // corsモジュールでは上手くCORSできないため、Server作成時の引数にオプションを追加する
        origin: "*",
        methods: ["GET", "POST"],
    },
});

ブラウザからの接続時の挙動

以下の記載をすることで、ブラウザから接続された際にログを出力することができる。

io.on("connection", (socket) => { 
    console.log("a user connected");
});

また、接続しているときに切断された場合は再度ログを出力するためには、以下の記載に変更する。接続されたときの処理の中に、切断されたときの処理が記載されていることに注意する。

io.on("connection", (socket) => { // ブラウザから接続されたときの処理
    console.log("a user connected");
    socket.on("disconnect", () => { // ブラウザが切断したときの処理
        console.log("user disconnected");
    });
});

画面サーバ側の設定

socket.ioとsocket.io-clientをインストール

画面サーバにモジュールをインストールする。

$ yarn add socket.io-client

もしかしたらsocket.ioは不要かも。

$ yarn add socket.io

以下のページを参照。

Client Initialization | Socket.IO

ちなみに、socket.io-clientをインストールしない方法としてindex.htmlに以下記載を追加したり色々試してみたが、うまくいかなかった。

<script src="/socket.io/socket.io.js"></script>

App.tsxの変更

App.tsxに以下記載を追加する。

App.tsx

import React from "react";
import "./App.css";
// socket.io-clientをインポートする
import { io } from "socket.io-client";

function App() {
    // Webサーバとの接続を確立
    // ※Webサーバと別ドメインの場合には、io()に引数が必要
    const socket = io("http://localhost:3000");
   // サーバに接続できた場合のイベント処理を定義する
    socket.on("connect", () => {
        console.log(`socket.connectを出力`);
        console.log(socket.connect()); // サーバに接続できたかどうかを表示
    });

    return (
        <div className="App">
            <h1>画面サーバからの返却</h1>
        </div>
    );
}
export default App;

解説

io()

以下の記載でWebサーバに接続している。

    const socket = io("http://localhost:3000");

ドメインの異なるWebサーバに接続する際は引数にURLを入れる必要がある。

socket.on

    socket.on("connect", () => {
});

socket.on()は、イベント名と処理を引数に取る関数。イベント名は自分で決めることができる。このイベント名をキーにしてサーバと情報をやり取りする。

一方で、"connect"は事前に定義された特別なイベントであり、サーバに接続したことを示す。今回のように書くとサーバ接続時に実行したい処理を記載できる。 socket.io

socket.connect()

socket.connect()を利用すると、サーバへの接続時の情報を取得できる。 socket.io

接続できたかどうかの二値だけであれば、socket.connected()が使える。

接続結果

Webサーバと画面サーバを起動して、画面サーバlocalhost:8000にアクセスすると、以下のようにコンソールに接続情報が表示された。

ブラウザの表示
ブラウザの表示

また、画面サーバ側もコンソールログが表示されていることが確認できた。

$ node index.js
Web server is on. PortNumber is 3000.
a user connected
a user connected

※1回ブラウザにアクセスすると2回接続しているように見えるので要調査。

おわりに

画面サーバ(React)とWebサーバ(Node.js)を別々に構築して、クライアントとWebサーバ間をSocket.ioで接続することができた。

関連記事

つづき:チャットアプリの基礎を作成する

tomiko0404.hatenablog.com