LoginSignup
1
0

More than 3 years have passed since last update.

react-router-domでCannnot Getとなった時の対処法

Posted at

背景

いつものようにreact-router-domを利用していると急にCannot Getとか言われて🤔になったので、備忘録として
残しておく。WhyHowを突き詰めることで知識と対応力をつけていきます。💪
ちなみにwebpackを利用しているため、今回はそちらの解決方法を紹介するつもりです。
間違っている点や疑問点はビシビシコメントください🤖

Why

スクリーンショット 2021-03-06 1.11.38.png

そもそも何でこんな問題が発生しているのかについて考えいきましょう!
ブラウザはhttps://sample.com/にアクセスするとサーバーサイドに問い合わせが飛びます。
サーバーは/(index.html)を求めるものだと判断してindex.htmlをレスポンスします。
そのため、もしhttps://sample.com/hello.htmlにアクセスして、hello.htmlが存在しない、かつ特にNot Found処理をしていない場合はCannot GETになってしまいます。

今回の場合、/sampleにアクセスが入り、サーバーはsampleファイルが見つからずこのような結果になってしまってます。

How

ここからは解決策を見ていきましょう!!
webpackを利用している場合dist等のプロジェクトフォルダーがビルドを行うことで、吐き出されていると思われます。
全てのURLに対してhtmlファイルを吐き出すのはよくないでしょう。(SPAじゃない)
それではどのように解決するかというとwebpack.configに次のような設定を追加しましょう!!

webpack.config.js
 output: {
    ....
    publicPath: '/'
 },
 devServer: {
    ...
    historyApiFallback: true,
  },

publicPathhistoryApiFallbackの2行を追加しただけで動くようになりました。
これら2つの設定がどのような動きをするのか見てみましょう。

publicPath

公式には次のようにあります。

The publicPath configuration option can be quite useful in a variety of scenarios. It allows you to specify the base path for all the assets within your application.

公式にあるようにCSSJavaScript等のasset群に対して、ベースURLを提供します。 下記のようにpublic Pathを指定するとpathが変更されていることがわかります。

webpack.config.js
 output: {
    ....
    publicPath: 'https://asset.com/'
 },
dist/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Hello World</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link href="https://asset.com/styles/index.css" rel="stylesheet"></head>
  <body>
    <div id="root"></div>
  <script defer src="https://asset.com/scripts/bundle.js"></script></body>
</html>

url-loader等に噛ませることも可能で、本番環境で画像等をCDNを利用して配信する場合、環境変数を通してローカルと本番環境でファイルpathの変更できます。
実は今回の問題に対してpublicPathの設定が必要な場合と、そうでない場合の2種類があります。
ほとんどの場合publicPathを指定しないで後述するhistoryApiFallbackを設定してあげることで動くのですが、プロジェクトのフォルダ構成やそれこそCDNの関係で必要となる場合があるので適宜設定してあげましょう。

historyApiFallback

When using the HTML5 History API, the index.html page will likely have to be served in place of any 404 responses. Enable devServer.historyApiFallback by setting it to true:

そのままですね。これをtrueにしてあげることで、ファイルが見つからなった場合にindex.htmlを返すようになります。
試しにプロジェクトファイルに2つのHTMLファイルを用意します。 この時の注意点ですが、HtmlWebpackPluginはデフォル設定だとfilenameindex.htmlで吐き出してしまうので、どちらかにfilenameを追加しましょう。

webpack.config.js
 plugins: [
    ....
    new HtmlWebpackPlugin({
      template: path.resolve(SRC_PATH, "./index.html"),
      inject: "body",
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(SRC_PATH, "./sample.html"),
      filename: "sample.html",
    }),
  ],

これで/sample.htmlの場合はファイルが存在するので、https://hoge.com/sample.htmlの場合はsample.htmlがレスポンスされます。それ以外の場合はindex.htmlがレスポンスされます。
historyApiFallbackを利用することでCannnot GET問題は解決できます。

参考

【意訳】Webpackの混乱ポイント

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0