背景
Reactで作成したSPAをECS上のnginxでホスティングしました。
そこで、ローカルとホスティングで動作が異なりました。
最初の画面が/login
というURLで表現されています。
アドレスバーに/login
と表示されてまして、ローカルでリロード(Command+R)すると、同じログイン画面が表示されます。一方、ホスティングしたものは「404 NOT FOUND」が表示されます。
ローカルと同じようにログイン画面を表示したいので、この事象と対応策について調べることにしました。
historyApiFallbackの実装が必要
この事象は「あるある」なようで、historyApiFallbackが必要ということがわかりました。
ローカルで動作確認するときは、npm start
で動かしています。このときはwebpack-dev-server
が起動します。このwebpack-dev-server
は、historyApiFallback オプションが有効になっており、たとえば/login
などのルートにアクセスされた場合でも常にindex.html
を返すようになっています。ブラウザが受け取るのはアプリケーションのエントリーポイントとなるindex.html
であり、React Routerなどのクライアント側のルーティングライブラリが正しく動作します。
一方、渡しはDockerにnginxを入れて、実装しました。
nginxは、デフォルトではリクエストされたパスに対応する静的ファイルを探します。 なので、例えばブラウザで/loginに直接アクセスすると、そのパスに対応するファイルが存在しないため、「404 NOT FOUND」エラーが返されるというわけです。
historyApiFallbackとは
で、ここでChat−GPTにhistoryApiFallbackとは何かを改めて聞いてみました。
目的
Q:historyApiFallbackの目的を教えて。
A:存在しないパスへのリクエストがあった場合に、404 エラーを返さず、常に index.html を返すことで、SPA のクライアントサイドルーティングを正しく機能させるための仕組みです。
利用シーン
Q:どんなときに使用するの?
A:直接URLにアクセスしてもアプリが正しく表示されるようにするために使用されます。
実装
nginxのdefault.conf
を以下のようにします。なお、以下は抜粋です。
server {
listen 8080;
listen [::]:8080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
ポイントは以下の部分です。
try_files $uri $uri/ /index.html;
リクエストされたURIに対してファイルを探す順序を指定しています。まず、リクエストされたURIに対応するファイル ($uri)
を探し、次にディレクトリ($uri/)
を探し、それらが見つからない場合はindex.html
を返すという設定です。