EY-Office ブログ

長年使っているのにcreate-react-appのproxy設定を知らなかった

あるReactのコードを読んでいてcreate-react-appの設定にproxyがある事を知りました。create-react-appというか、その中で動くwebpackの開発サーバー(DevServer)の設定にdevServer.proxyがありました。

create-react-appも早い時期から使っていましたし、昔はwebpackを使っていたのに、このproxy設定を知りませんでした。😅

Proxy https://en.wikipedia.org/wiki/Proxy_serverより

オリジン間リソース共有 (CORS)

JavaScriptは素晴らしいユーザビリティーのあるWebアプリを作る事ができる源泉です。しかし, JavaScriptはWebページをアクセスすると確認も無く実行されてしまうので、悪意あるコンピュータウイルスを作るツールとして使われてしまってはとても不幸な事になります。

そのために、ブラウザーで動くJavaScriptはPC上の任意のファイルを読み書きする事はできません(ファイル選択で選ばれたファイル等はアクセスできますが)。
また、JavaScriptが通信APIを使って通信できるサーバーは原則そのJavaScriptが読み込まれたWebサーバーに限るという同一オリジンポリシー (same-origin policy) があります。

ただし、これでは不便なことがあります。例えばWebサーバーのURLが https://www.server.com で、アプリを実行するバックエンドのサーバーのURLが https://api.server.com の場合Webサーバーから読み込まれたJavaScriptはバックエンドのサーバーと通信できません。
このような場合に対応できるようにJavaScriptにはオリジン間リソース共有 (CORS)という仕様が決められていてバックエンドサーバー、Webアプリ両方で対応コードを書く事で対応できます。

もちろん、Webサーバーにリバースプロキシ(Reverse proxy)を入れて特定のURL例えばhttps://www.server.com/api へのアクセスはhttps://api.server.comに転送されるようにし、同一オリジンにする方法もあると思います。

create-react-appのproxy設定

Reactアプリを開発環境をcreate-react-appで作成した場合http://localhost:3000に開発サーバーが起動されます。開発用のバックエンドがDocker等でhttp://localhost:8080に起動されている場合は多いとおもいます。この場合ホスト名は同じですがポート番号が違うので同一オリジンとはみなされず、開発環境でもオリジン間リソース共有 (CORS)を行っておく必要があります。

このような場合は、package.jsonファイルに"proxy": "http://localhost:8080"を書きます。 詳細は → create-react-appのproxy設定

すると開発サーバーは、ブラウザーからのリクエストヘッダーにAccept: text/htmlが含まれてない場合に、バックエンドサーバーへのリクエストだと判断しhttp://localhost:3000http://localhost:8080に置き換えバックエンドサーバーにアクセスします。
このようにバックエンドへのアクセスは開発サーバーが行っているので、ブラウザーからは同一オリジンになります。

下のコードをproxyの環境で動かすとfetch("/api/users")http://localhost:8080/api/usersのバックエンドサーバーへのアクセスになります。

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

type User = {
  id: number
  name: string
  email: string
};

export const App: React.FC = () => {
  const [users, setUsers] = useState<User[]>([])
  useEffect(() => {
    (async() => {
      const res = await fetch("/api/users")
      const data = await res.json()
      setUsers(data)
    })()
  }, [])

  return (
    <>
      <h1>Hello Word!</h1>
      {users.map(u => <p>{u.email}</p>)}
    </>
  )
}

ただし、特定のURLはこのバックエンドサーバーに対応させたいとか、URLを書き換えたいなどの高度な設定をしたい場合は、http-proxy-middleware npmをインストールし、以下のようなsrc/setupProxy.jsファイルを準備する必要があります。
これはwebpackの開発サーバーのproxy機能です。

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(createProxyMiddleware('/users', {target: 'http://localhost:8080'}));
};

長い間使っていてもドキュメントを全て眺めているわけではないので、このような事がおきますね。たまには自分の使っているツールのドキュメントを読み直してみるのも良いかもしれませんね。😊

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ