ローカルで実行した React アプリでもサーバーの API を利用するには

結果、package.json に以下の様な proxy を設定すれば OK という話なのですが、やりたいことから順に説明していきます。

  "proxy": "http://192.168.0.10/"

API のポートが 80 で無く、例えば 8080 なら、それも指定します。

  "proxy": "http://192.168.0.10:8080/"

やりたいこと

開発サーバー (192.168.0.10)

  • バックエンドの API のサービスが用意できている
  • 開発したフロントエンドのアプリもビルドして配置する

開発するPC (192.168.0.20)

  • フロントエンドのアプリを create-react-app で生成されるものを元に開発する
  • ローカルで実行する http://localhost:3000/ からサーバーの API を呼びたい

という太字の部分が「やりたいこと」になります。
何故なら単純に開発するPC側から、

fetch('http://192.168.0.10/v1/item')

しても、

Access to fetch at 'http://192.168.0.10/v1/item' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

というエラーでアクセスはできません。

試してみる:バックエンドの作成

簡単なものを express で作ってみます。

const express = require('express');
const app = express();
const port = 80;

app.get('/v1/item', (req, res) => {
  const resObj = {
    timestamp: new Date().toString(),
    message: 'Hello World!'
  };
  res.send(resObj);
});

app.listen(port, () => {
  console.log(`listening:${port}`)
});

サーバー側で次のコマンドで実行

node app.js

試しにブラウザからアクセスしてみて、

{"timestamp":"Sat Sep 25 2021 21:28:05 GMT+0900 (日本標準時)","message":"Hello World!"}

の様な文字列が表示されれば OK です。

試してみる:フロントエンドの作成

ベースは create-react-app で生成します。

npx create-react-app front-example --template typescript

修正するのは、App.tsx と package.json になります。

import React, {useEffect, useState} from 'react';

function App() {
  const [value, setValue] = useState<string>();
  useEffect(() => {
    fetch('/v1/item')
    .then(async res => setValue(JSON.stringify(await res.json(), null, 2)));
  }, []);
  return (
    <pre>{value}</pre>
  );
}

export default App;
{
  "proxy": "http://192.168.0.10/",
  "name": "front-example",
  "version": "0.1.0",
  "private": true,
(以下省略)

ローカルで実行します。

yarn start

ブラウザの http://localhost:3000/ に

{
  "timestamp": "Sat Sep 25 2021 21:40:27 GMT+0900 (日本標準時)",
  "message": "Hello World!"
}

の様な文字が表示されれば OK です。

コメント