WEBサーバと画面サーバを作成して相互に通信させる
はじめに
今回の記事の目的
自分で画面サーバとWebサーバを作成し、通信させる。 具体的には、画面サーバがWebサーバから値を取得して、画面表示する。
また、このときに必要になるCORSについて理解する。
前提
開発環境
- ローカル環境はLinuxを利用する。
Windows上にLinux環境を構築する方法
Linux仮想環境:Vagrantの立ち上げ方メモ - エンジニアを目指す日常ブログ
docker環境
必須ではないが、今回は画面サーバ用のdockerコンテナとWebサーバ用のdockerコンテナを2つ用意した。
将来的にAWS ECSに載せたいのでこの構成にした。
dockerを立ち上げる方法メモ
tomiko0404.hatenablog.com
Webサーバの作成
WebサーバはNode.jsで作成した。
Webサーバの作成方法メモ。コンテナ上で実施しているので、「Node.js自体のインストール」は不要。 tomiko0404.hatenablog.com
画面サーバの作成
画面サーバはReact×Typescriptで構築した。
■Reactプロジェクトを作成する方法
tomiko0404.hatenablog.com
■Reactアプリを編集する方法
tomiko0404.hatenablog.com
全体構成
ローカルフォルダの構成は以下となっている。
├── back ※backendコンテナにマウントしている │ ├── index.js │ ├── node_modules │ ├── package-lock.json │ ├── package.json │ └── yarn.lock ├── docker │ ├── Dockerfile │ └── docker-compose.yml └── front ※frontendコンテナにマウントしている ├── README.md ├── node_modules ├── package.json ├── public ├── src ├── tsconfig.json └── yarn.lock
Webサーバの内容
Webサーバは、実行するとポート3000番でリクエストを待ち受け、GETメソッドを受け取ると、ステータスコード200、ボディ部に"Hello World from backend!!!"を返却するアプリにする。
index.js
の記載内容は以下のようにする(後ほど、CORSのために追記が必要)。
index.js
// expressをrequireする const express = require("express"); // ポート番号を変数に設定 const portNumber = 3000; // appオブジェクトを作成する const app = express(); // getメソッドで、ルートパスにアクセスしてきたときの処理を記載する app.get("/", (req, res) => { res.status(200).send("Hello World from backend!!!"); }); // リクエストを待ち受ける app.listen(portNumber); console.log(`PortNumber is ${portNumber}`);
node index.js
を実行した後、ブラウザにlocalhost:3000
を入力してアクセスすると、値が返ってきているのがわかる。
画面サーバの内容
画面サーバは、WebサーバにGETメソッドでHTTPアクセスして、応答された値をコンソールに表示した上で、画面にも表示するアプリとする。
axiosのインストール
HTTPで値を取得するために便利なaxiosモジュールをインストールする。
node@b0af091276ac:/app$ yarn add axios
App.tsxの作成
前提記事の通りにReact×Typescriptで作成した上で、今回、App.tsx
を以下のように記載する。
App.tsx
import React, { useState } from "react"; import axios from "axios"; import "./App.css"; function App() { const [msg, setMsg] = useState("なし"); // msgステートを作成し、初期値は"なし" axios .get("http://localhost:3000") // localhost:3000にアクセス .then((res) => { console.log(res.data); // 取得した値をコンソールに表示 setMsg(res.data); // msgステートに取得した値を格納 }) .catch((err) => console.log(err.responce)); return ( <div className="App"> <h1>{msg}</h1> // h1の中身にmsgステートの値を表示 </div> ); } export default App;
get
の中身はlocalhost:3000
ではなくhttp://localhost:3000
となることに注意する。(補完してくれるツールが多いため忘れてしまった)
Reactがわからない場合はこちらへ: Reactに入門した人のためのもっとReactが楽しくなるステップアップコース完全版 | Udemy
実際に画面サーバからWebサーバにアクセスすると、同一オリジンポリシーにより、はじかれる
画面サーバからWebサーバにアクセスする
Webサーバ側のコンテナでnode index.js
を実行した状態で、画面サーバ側でyarn start
を実行する。
Webサーバから値をとることができていないことがわかる。
エラーの内容は、「CORSポリシーにブロックされており、応答のヘッダに'Access-Control-Allow-Origin'が無いです」というもの。
Access to XMLHttpRequest at 'http://localhost:3000/' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
CORS(Cross-Origin Resource Sharing) について
少し勉強が必要。私の理解で一言にすると以下(正確ではない)。
■CORSとはそもそも何かの参考
なんとなく CORS がわかる...はもう終わりにする。 - Qiita
■具体的なCORSの解説
こちらによれば「単純な要求」と「単純ではない要求」で対処が変わるとのこと。(今回は単純な要求)
CORS とは? - JavaScript の基本 - JavaScript 入門
ヘッダを確認
Postmanを利用してローカルからWebサーバにアクセスした際のレスポンスのヘッダを確認すると、Access-Control-Allow-Origin
応答は無さそう。
異なるオリジンからのアクセスを許可する
すべてのAPIへのアクセスを許可する方法
CORS専用のモジュールがあるとのことなので、単純に使うのがよさそう。
corsモジュールインストール
Webサーバのdocker上で以下を実行する。
$ yarn add cors
index.jsの追記
以下の記載をindex.js
に追記する。
index.js
const express = require("express"); // CORSをインポートする const cors = require("cors"); const portNumber = 3000; const app = express(); // 全てのオリジンからのアクセスを許可する app.use(cors()); app.get("/", (req, res) => { res.status(200).send("Hello World from backend!!!"); }); app.listen(portNumber); console.log(`PortNumber is ${portNumber}`);
結果確認
ここで画面サーバ(localhost:8000
)にアクセスしてみると、Webサーバから値を取得できたことがわかる。
Postmanでアクセスしてみると、ヘッダに
Access-Control-Allow-Origin: "*"
が追加されているのがわかる。
一部のAPIへのアクセスを許可する方法
個別のAPIへのアクセスを許可するには、get
メソッドの引数に設定する。
app.get("/", cors(), (req, res) => { res.status(200).send("Hello World from backend!!!"); });
参考資料:
express.jsのcors対応 - Qiita
特定のオリジンからのアクセスのみ許可する場合
App.tsx
を以下のように書き換える。
App.tsx
const express = require("express"); const cors = require("cors"); const portNumber = 3000; const app = express(); // 一部のオリジンからのアクセスを許可する const corsOptions = { origin: ["http://localhost:8000", "http://example.com"], }; app.use(cors(corsOptions)); app.get("/", (req, res) => { res.status(200).send("Hello World from backend!!!"); }); app.listen(portNumber); console.log(`PortNumber is ${portNumber}`);
参考資料:
ExpressとTypeScript APIにCORSサポートを追加する方法
おわりに
今回Webサーバと画面サーバを通信させることができた。また、CORSへの理解が深まった。