react を使って SPA を構築した場合、静的リソースが存在しない URL を直接指定すると 404 Error になる

この記事の概要(忙しい方はここだけ見れば良いです)

react-router のルーティング設定だけでは、静的リソースの存在しないページを直接 URL で指定してアクセスすると 404 Error になります。 URL を直接指定しても目的のページを表示させるようにするには、サーバでフォールバックを設定しましょう。webpack-dev-server であるならば historyApiFallback: true を設定することで、404 Error を回避できます。

react-router のルーティングはあくまでクライアント上での(サーバーにリクエストを送らない)ページ遷移に用いられるもので、サーバの方で routing が設定されている OR 静的リソースが存在しないページへのアクセスは 404 Error になります。routing が設定されていない(静的リソースが存在しない)ページがサーバに要求された場合、トップレベルの URL (http://localhost/ ) のコンテンツをクライアントに返した後で、react-router による遷移がなされるような(フォールバック)設定をする必要があります。

詳細説明

環境

frontend: react + redux backend: nodejs (webpack-dev-server)

状況

原因の詳細

https://teratail.com/questions/26245:react-routerでURLパラメータを指定した際、URL直打ちだと404になります から引用

トップページから react-router でページを辿る場合以下の遷移になりますが、

http://hoge.com/
http://hoge.com/index.html => 実際ブラウザが読み込んでいるのはこのファイル
http://hoge.com/detail/1 => react-router が対応するコンポーネントを読み込んで表示。このとき History API により URL が書き換わっている
ブラウザリロード、またはダイレクトにアクセスした場合、以下のようになります。

http://hoge.com/detail/1 => このリソースは存在しないので 404 になる
したがって、リソースが存在しない場合 /index.html に rewrite してあげないといけないはずです。rewrite の設定ができている場合、ダイレクトにアクセスした場合の挙動は以下のようになります。

http://hoge.com/detail/1
http://hoge.com/index.html => URLが rewrite された結果ブラウザが読み込んでいるのはこのファイルになる
http://hoge.com/detail/1 => react-router が対応するコンポーネントを読み込んで表示

解決方法

webpack.config.js の devServer に "historyApiFallback: true" を追加する

devServer: {
  historyApiFallback: true,
  contentBase: 'www',
  port: 4000,
  inline: true
}

 これで存在しないリソースに対するアクセスは、/index.html に フォールバックされるようになります。

参考

blog.mismithportfolio.com