あるReactのコードを読んでいてcreate-react-appの設定にproxyがある事を知りました。create-react-appというか、その中で動くwebpackの開発サーバー(DevServer)の設定にdevServer.proxyがありました。
create-react-appも早い時期から使っていましたし、昔はwebpackを使っていたのに、この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:3000
をhttp://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'}));
};
長い間使っていてもドキュメントを全て眺めているわけではないので、このような事がおきますね。たまには自分の使っているツールのドキュメントを読み直してみるのも良いかもしれませんね。😊