React-routerのURLが更新または手動での書き込み時に機能しない


655

私はReact-routerを使用しており、リンクボタンをクリックしている間は問題なく動作しますが、Webページを更新すると、必要なものが読み込まれません。

たとえばlocalhost/joblist、リンクを押してここに到着したので、私は入っており、すべてが順調です。しかし、ウェブページを更新すると、次のようになります。

Cannot GET /joblist

デフォルトでは、このように機能しませんでした。最初、私は私のURLをそのまま使用localhost/#/しましたがlocalhost/#/joblist、それらは完全に問題なく動作しました。しかし、私はこの種のURLが好きではないので、それを消去しようとすると#、私は書きました:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

この問題はでは発生しません。この問題はlocalhost/常に私が欲しいものを返します。

編集:このアプリは単一ページであるため/joblist、サーバーに何も要求する必要はありません。

EDIT2:私のルーター全体。

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

あなたは、あなたのメインのツーリングページをロードするためにhtaccessファイルを使用して使用するようにルータを指示しない限り、それは動作しませんlocation.pathname ...
チャールズ・ジョン・トンプソンIII

どのようにしてその#シンボルを消去しましたか?ありがとうございました!
SudoPlz

4
反応アプリをS3バケットでホストしている場合は、エラードキュメントをに設定するだけindex.htmlです。これは、index.html何があってもヒットすることを確認します。
Trevor Hutto 2016

私の場合、Windowsでは正常に機能しますがLinuxでは機能しません
Ejaz Karim

これは私の問題を解決する助け参照です:github.com/facebook/create-react-app/blob/master/packages/...
jimbotron

回答:


1096

受け入れられた回答のコメントとこの質問の一般的な性質(「機能しない」)を見ると、ここに含まれる問題についての一般的な説明にはこれが良い場所だと思いました。したがって、この回答は、OPの特定の使用例に関する背景情報/詳細を目的としています。我慢してください。

サーバー側とクライアント側

これについて理解する最初の大きなことは、URLが解釈される場所が2つあるのに対し、「昔」では1つしかなかったということです。以前は、人生が単純だったとき、一部のユーザーhttp://example.com/aboutはサーバーにリクエストを送信し、サーバーはURLのパス部分を検査して、ユーザーが概要ページをリクエストしていると判断し、そのページを送り返しました。

React-Routerが提供するクライアント側ルーティングでは、物事はそれほど単純ではありません。最初、クライアントにはまだJSコードがロードされていません。したがって、最初のリクエストは常にサーバーに対して行われます。次に、ReactやReact Routerなどをロードするために必要なスクリプトタグを含むページを返します。これらのスクリプトがロードされた場合にのみ、フェーズ2が開始されます。フェーズ2では、たとえばユーザーが[About us]ナビゲーションリンクをクリックすると、URLはローカルでのみ変更http://example.com/aboutHistory APIによって可能になります)、サーバーへのリクエストは行われません。。代わりに、React Routerはクライアント側で処理を実行し、レンダリングするReactビューを決定してレンダリングします。aboutページがREST呼び出しを行う必要がないと想定すると、REST呼び出しはすでに完了しています。サーバー要求が発生せずに、ホームから会社概要に移行しました。

つまり、基本的にリンクをクリックすると、アドレスバーのURLを操作するJavascriptが実行され、ページが更新されることはありません。これにより、React Router がクライアント側でページ遷移を実行します。

しかし、アドレスバーにURLをコピーして貼り付け、友人に電子メールで送信するとどうなるかを考えてみましょう。友達はまだあなたのウェブサイトをロードしていません。つまり、彼女はまだフェーズ1です。彼女のマシンではまだReact Routerが実行されていません。したがって、彼女のブラウザはへのサーバー要求を行いhttp://example.com/aboutます。

そして、これがあなたの悩みの始まりです。これまでは、静的HTMLをサーバーのWebルートに配置するだけで済むでしょう。ただし、サーバーから要求された場合404、他のすべてのURL エラーが発生します。これらの同じURL は、React Routerがルーティングを実行しているため、クライアント側正常機能ますが、サーバーに理解させない限り、サーバー側では失敗ます。

サーバー側とクライアント側のルーティングを組み合わせる

必要であればhttp://example.com/aboutサーバ-とクライアント側の両方の仕事にURLを、あなたはサーバ-クライアント側の両方にそれのためのルートを設定する必要があります。理にかなっていますか?

そして、これがあなたの選択が始まるところです。解決策は、ブートストラップHTMLを返すキャッチオールルートを介して問題を完全に回避することから、サーバーとクライアントの両方が同じJSコードを実行する完全な同形アプローチにまで及びます。

問題を完全に回避する:ハッシュ履歴

ハッシュ歴史の代わりに、ブラウザの歴史、このようなものになりますについてのページのためのあなたのURL: http://example.com/#/about ハッシュ(後の部分#)のシンボルをサーバーに送信されません。したがって、サーバーはhttp://example.com/予想どおりにインデックスページのみを表示して送信します。React-Routerが#/aboutパーツを受け取り、正しいページを表示します。

欠点

  • 「醜い」URL
  • この方法では、サーバー側のレンダリングはできません。検索エンジン最適化(SEO)に関する限り、Webサイトはコンテンツがほとんどない単一のページで構成されます。

キャッチオール

このアプローチではブラウザ履歴を使用しますが、に送信/*するサーバーでキャッチオールを設定するだけでindex.html、ハッシュ履歴の場合とほぼ同じ状況が効果的に得られます。ただし、クリーンなURLはあり、ユーザーのお気に入りをすべて無効にすることなく、後でこのスキームを改善できます。

欠点

  • セットアップがより複雑
  • まだ良いSEOはありません

ハイブリッド

ハイブリッドアプローチでは、特定のルートに特定のスクリプトを追加することにより、包括的なシナリオを拡張します。簡単なPHPスクリプトをいくつか作成して、コンテンツが含まれているサイトの最も重要なページを返すようにすると、Googlebotは少なくともページの内容を確認できます。

欠点

  • セットアップがさらに複雑
  • あなたが特別な扱いをするそれらのルートにのみ良いSEO
  • サーバーとクライアントでコンテンツをレンダリングするためのコードの複製

同形

Node JSをサーバーとして使用して、両端で同じ JSコードを実行できるとしたらどうでしょう。これで、すべてのルートが単一のreact-router構成で定義されました。レンダリングコードを複製する必要はありません。これは、いわば「聖杯」です。サーバーは、クライアントでページ遷移が発生した場合の最終的なものとまったく同じマークアップを送信します。このソリューションは、SEOに関して最適です。

欠点

  • サーバー JSを実行する(できる)必要があります。Java icw Nashornを試してみましたが、うまくいきません。実際には、ほとんどの場合、Node JSベースのサーバーを使用する必要があります。
  • 多くのトリッキーな環境問題(windowサーバー側などで使用)
  • 急な学習曲線

どちらを使用すればよいですか?

あなたが逃げることができるものを選択してください。個人的には、キャッチオールは設定するのに十分単純であると思うので、それは私の最低限でしょう。この設定により、時間の経過とともに物事を改善することができます。すでにNode JSをサーバープラットフォームとして使用している場合は、同形アプリを実行することを検討します。はい、最初は難しいですが、慣れると、問題に対する非常にエレガントな解決策になります。

だから、基本的に、私にとっては、それが決定的な要因になるでしょう。サーバーがNode JSで実行されている場合、同型になります。それ以外の場合は、キャッチオールソリューションに移行し、時間の経過とSEO要件に応じて拡張(ハイブリッドソリューション)します。

Reactを使用した同型(「ユニバーサル」とも呼ばれます)レンダリングの詳細を知りたい場合は、このテーマに関する優れたチュートリアルがあります。

また、開始するには、いくつかのスターターキットを確認することをお勧めします。テクノロジースタックの選択に一致するものを選択してください(ReactはMVCの単なるVであり、完全なアプリを構築するにはさらに多くのものが必要であることを忘れないでください)。まず、Facebook自体が公開しているものを見てみましょう。

または、コミュニティによる多数の1つを選択してください。それらすべてをインデックスに登録しようとする素晴らしいサイトがあります:

私はこれらから始めました:

現在、上記の2つのスターターキットに触発された自家製バージョンのユニバーサルレンダリングを使用していますが、現在は古くなっています。

あなたの探求で頑張ってください!


2
素晴らしいポスト 同形反応アプリのスターターキットを使用することをお勧めしますか?もしそうなら、あなたが好むものの例を挙げてもらえますか?
クリス

1
@ Paulos3000使用しているサーバーによって異なります。基本的には、ルートを定義/*し、HTMLページで応答するようにします。ここでトリッキーなことは、このルートで.jsファイルと.cssファイルのリクエストを傍受しないことを確認することです。
Stijn de Witt 2016

2
@ Paulos3000関連する質問については、Apache / phpExpress / jsJ2E / Javaをご覧ください。
Stijn de Witt 2016

1
こんにちは、私はハッシュソリューションを試していますが、うまくいきません。取得createMemoryHistory is not a functionエラー。見てマインド?stackoverflow.com/questions/45002573/...
レオン・ギャバン

5
@LeonGabanこの回答が書かれてから、React Routerは実装を変更したようです。これで、履歴ごとに異なるルーターインスタンスが作成され、バックグラウンドで履歴の構成が行われます。基本的な原則は同じです。
Stijn de Witt 2017

116

ここでの答えはすべて非常に役に立ちます。私にとってうまくいったのは、ルートを期待するようにWebpackサーバーを構成することでした。

devServer: {
   historyApiFallback: true,
   contentBase: './',
   hot: true
},

historyApiFallbackは、この問題を解決したものです。これでルーティングが正しく機能し、ページを更新したり、URLを直接入力したりできます。ノードサーバーでの回避策について心配する必要はありません。この回答は明らかにwebpackを使用している場合にのみ機能します。

編集:これが必要な理由の詳細については、ここで私の答えを参照してくださいhttps//stackoverflow.com/a/37622953/5217568


16
Webpackチーム、本番環境で開発サーバーを使用しないことを推奨していることに注意してください。
Stijn de Witt

5
一般的な開発目的では、これが最良のソリューションです。historyApiFallback十分なものです。他のすべてのオプションについては、フラグを使用してCLIからも設定できます--history-api-fallback
Marco Lazzeri、2016年

2
@Kunokありません。これは開発のための迅速な修正ですが、まだプロダクションのために何かを理解する必要があります。
Stijn de Witt

contentBase: ':/'アプリのファイルにURLからアクセスできるようにする
Nezih

85

.htaccessファイルを変更してこれを挿入できます:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]
</IfModule>

私が使用してreact: "^16.12.0"おり、react-router: "^5.1.2" この方法はキャッチオールであり、おそらくあなたが始めるのに最も簡単な方法です。


3
これはうまくいきます!アプリを再構築したくない場合は、最も簡単です
mhyassin 2018

7
最初の行としてRewriteEngine Onを忘れないでください
Kai Qing

3
この回答は、Apacheサーバーの構成を指していることに注意してください。これはReactアプリの一部ではありません。
Colton Hicks

上記の答えが理解できませんでした。私のリンクがライブでまったく機能しないと言った家庭教師はいなかった。ただし、この単純なhtaccessファイルは機能しました。ありがとう
Thomas Williams

これはnext.js静的エクスポートでも機能します。Tomcatはノードに似ていないため、next.js静的エクスポートにはこの追加の構成が必要です。
giri-jeedigunta

62

以下のためにルータV4に反応ユーザーは:

他の回答で述べられているハッシュ履歴の手法でこの問題を解決しようとする場合は、

<Router history={hashHistory} >

V4では機能しません。HashRouter代わりに使用してください:

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

リファレンス:HashRouter


HashRouterがこの問題を修正する理由について詳しく教えてください。あなたが提供したリンクは私にそれを説明していません。また、パスにハッシュを隠す方法はありますか?私はそれでこの問題404 ...にBrowserRouterが、RANを使用していた
イアン・スミス

29

ナビゲーションは、クライアントとサーバーのどちらで行われるかに応じて、2つの異なる方法で呼び出すことができます。クライアント側操作用に構成されています。重要なパラメーターは、runメソッドの 2番目のパラメーターである場所です。

React Router Linkコンポーネントを使用すると、ブラウザーのナビゲーションがブロックされ、transitionToが呼び出されてクライアント側のナビゲーションが行われます。HistoryLocationを使用しているため、HTML5履歴APIを使用して、アドレスバーの新しいURLをシミュレートすることにより、ナビゲーションの錯覚を完成させています。古いブラウザを使用している場合、これは機能しません。HashLocationコンポーネントを使用する必要があります。

リフレッシュを押すと、すべてのReactおよびReact Routerコードをバイパスします。サーバーはリクエストを取得し、/joblist何かを返す必要があります。サーバーではrun、正しいビューをレンダリングするために、要求されたパスをメソッドに渡す必要があります。同じルートマップを使用できますが、おそらく別の呼び出しが必要になりますRouter.runます。Charlesが指摘しているように、URLの書き換えを使用してこれを処理できます。別のオプションは、node.jsサーバーを使用してすべてのリクエストを処理し、場所の引数としてパス値を渡すことです。

たとえば、次のようになります。

var app = express();

app.get('*', function (req, res) { // This wildcard method handles all requests

    Router.run(routes, req.path, function (Handler, state) {
        var element = React.createElement(Handler);
        var html = React.renderToString(element);
        res.render('main', { content: html });
    });
});

リクエストパスがに渡されていることに注意してくださいrun。これを行うには、レンダリングされたHTMLを渡すことができるサーバー側のビューエンジンが必要です。renderToStringサーバーでReact を使用して実行する際には、他にもいくつかの考慮事項があります。サーバーでページがレンダリングされた後、アプリがクライアントに読み込まれると、再度レンダリングされ、サーバー側でレンダリングされたHTMLが必要に応じて更新されます。


2
すみませんすみません、次のステートメントについて説明していただけますか。なぜそれが起こるのですか?
VB_

Reactルーターは通常、ブラウザー内でのみ異なる「パス」を処理するために使用されます。これを行う一般的な方法は2つあります。古いスタイルのハッシュパスと新しい履歴APIです。ブラウザの更新によりサーバー要求が行われ、クライアント側の反応ルーターコードがバイパスされます。サーバー上のパスを処理する必要があります(ただし、履歴APIを使用している場合のみ)。あなたはこれのために反応ルータを使うことができます、しかしあなたは私が上で説明したものと同様の何かをする必要があるでしょう。
Todd

とった。しかし、サーバーが非JS言語(Javaとしましょう)を使用している場合はどうすればよいでしょうか。
VB_

2
申し訳ありませんが、「ルート以外」のルートを表示するには高速サーバーが必要ですか?同型写像の定義の概念にデータフェッチが含まれていないことに最初に驚きました(サーバー側でデータを表示する場合は明らかにSEOが必要ですが、同型写像はそれを主張しています)。今、私は「WTF反応」のように真剣に…間違っている場合は修正してください。ルートをレンダリングするためにember / angular / backboneにはサーバーのものが必要ですか?ルートを使用するためのこの肥大した要件を本当に理解していません
Ben

1
反応アプリケーションが同形でない場合、react-routerでの更新が機能しないということですか?
Matt

28

index.html headに以下を追加します。

<base href="/">
<!-- This must come before the css and javascripts -->

次に、webpack開発サーバーで実行する場合は、このコマンドを使用します。

webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback

--history-api-fallback 重要な部分です


これはうまくいきました!どのようにしてそのソリューションを入手/発見したかについてさらに読むためのリンクはありますか?
justDan

1
すみません、仲間。試行錯誤の実績のある手法でそれを見つけました。
Efe Ariaroo

それの価値が言及すること、あなたではありませんベースのhref使用している場合は/、その後HashRouter(あなたはハッシュルーティング使用している場合)しません仕事を
ロビーエーヴリル

<base href = "/">タグがそれを行いました。これをありがとう。Webpack開発サーバーは、パス/ <bundle>からバンドルを取得しようとし続け、失敗しました。
Malisbad

27

今、create-react-appを使用してウェブサイトを作成しましたが、ここで同じ問題が発生しました。パッケージBrowserRoutingから使用していreact-router-domます。私はNginxサーバーで実行していて、それを解決したのは以下を追加することでした/etc/nginx/yourconfig.conf

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

これは、.htaccessAppacheを実行している場合に以下を追加することに対応します

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

これはFacebook自身が提案する解決策のようでもあり、ここで見つけることができます


1
うわー、nginxのこのような単純なソリューション。新しいnginxユーザーとして、魅力のように動作します。コピーして貼り付けてください。公式のfbドキュメントにリンクするための+1。行く方法。
user3773048

参考までに、私はnginxとAngularアプリでAWSインスタンスを使用しています。これは機能します。
ディエゴサルミエント

あなたは私を助けてくれる。昨日から問題を解決しようとしていましたが、いくつかの解決策に疲れましたが、失敗しました。最後に、このルーターの問題を解決するのを手伝ってくれました。ああ、兄弟に感謝
Sharifur Robin

"react": "^ 16.8.6"、 "react-router": "^ 5.0.1"に必要な違いはありますか?私はこれらのソリューション(nginxとapacheの両方)を試しましたが、機能しません。
Mark A. Tagliaferro

Facebookはこれに関するドキュメントを変更していないので、手順は同じであるとしか想定できません。私はしばらくそれを試していません。
アイディン

17

これはあなたの問題を解決することができます

プロダクションモードのReactJSアプリケーションでも同じ問題に直面しました。これが問題の2つの解決策です。

1.ルーティング履歴をbrowserHistoryの代わりに "hashHistory"に変更します。

<Router history={hashHistory} >
   <Route path="/home" component={Home} />
   <Route path="/aboutus" component={AboutUs} />
</Router>

次のコマンドを使用してアプリをビルドします

sudo npm run build

次に、ビルドフォルダーをvar / www /フォルダーに配置します。これで、アプリケーションはすべてのURLに#タグを追加して正常に動作します。お気に入り

localhost /#/ home localhost /#/ aboutus

解決策2:browserHistoryを使用した#タグがない場合、

ルーターに履歴= {browserHistory}を設定し、sudo npm run buildを使用してビルドします。

404 not foundページを解決するには、「conf」ファイルを作成する必要があります。confファイルは次のようになります。

端末を開き、以下のコマンドを入力します

cd / etc / apache2 / sites-available ls nano sample.conf以下の内容を追加します。

<VirtualHost *:80>
    ServerAdmin admin@0.0.0.0
    ServerName 0.0.0.0
    ServerAlias 0.0.0.0
    DocumentRoot /var/www/html/

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    <Directory "/var/www/html/">
            Options Indexes FollowSymLinks
            AllowOverride all
            Require all granted
    </Directory>
</VirtualHost>

次のコマンドを使用して、sample.confファイルを有効にする必要があります。

cd /etc/apache2/sites-available
sudo a2ensite sample.conf

次に、sudoサービスapache2 reloadまたはrestartを使用して、apacheサーバーをリロードするように求められます

次にlocalhost / buildフォルダーを開き、以下の内容の.htaccessファイルを追加します。

   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_FILENAME} !-l
   RewriteRule ^.*$ / [L,QSA]

これで、アプリは正常に動作しています。

注:0.0.0.0 ipをローカルIPアドレスに変更します。

これに関する疑義がある場合は、遠慮なくコメントを投稿してください。

他の方々のお役に立てれば幸いです。


最初のソリューションは機能し"react-router-dom": "^5.1.2"ますか?私は使用しています<BrowserRouter>
151291

16

AWS Static S3 Hosting&CloudFrontを介して反応アプリをホストしている場合

この問題は、CloudFrontが403 Access Deniedメッセージで応答して、S3フォルダーに/ some / other / pathが存在することを期待していたが、そのパスはReact-routerを使用したReactのルーティング内にのみ存在するために発生しました。

解決策は、配布エラーページルールを設定することでした。CloudFront設定に移動し、ディストリビューションを選択します。次に[エラーページ]タブに移動します。[カスタムエラーレスポンスの作成]をクリックして、403のエントリを追加します。これが取得するエラーステータスコードです。応答ページのパスを/index.htmlに設定し、ステータスコードを200に設定します。最終結果は、その単純さに驚かされます。インデックスページは提供されますが、URLはブラウザーに保持されるため、reactアプリが読み込まれると、URLパスが検出され、目的のルートに移動します。

エラーページ403ルール


1
これはまさに私が必要としたものです。ありがとうございました。
ジョナサン

つまり、すべてのURLは機能しますが、ステータスコード403を返しますか?不正解です。予期されるステータスコードは2xxの範囲内である必要があります。
Stijn de Witt

@StijndeWittあなたが正しく理解しているとは思いません。CloudFrontはすべてを処理します-クライアントには403ステータスコードが表示されません。再ルーティングはサーバー側で行われ、インデックスページがレンダリングされ、URLが維持され、結果として正しいルートが提供されます。
th3morg

@ th3morgああそうです。応答ステータスコードを200に入力することもできませんでした。基本的に、ステータス403をステータス200にマッピングしています...ほかの理由で結果として403が返された場合を除いて、問題ありません。このため、それを見ることができません。
Stijn de Witt

1
この@ th3morgに感謝します。この設定はマルチレベルパスでも機能しますか?ルートレベルのパス(domain / signup、domain / login、domain / <documentId>など)の場合、私にとってはうまく機能しますが、domain / document / <documentId>などのマルチレベルのパスでは機能しません。
Pargles

16

Webpack Dev Serverには、これを有効にするオプションがあります。を開いてpackage.json追加し--history-api-fallbackます。このソリューションは私のために働いた。

反応ルーターチュートリアル


3
それwebpack-dev-serverは問題ありませんが、プロダクションビルドでこれをどのように修正すればよいですか?
フセイン

12

IISでreactアプリをホストしている場合は、次を含むweb.configファイルを追加するだけです。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" path="/" responseMode="ExecuteURL" />
    </httpErrors>
  </system.webServer>
</configuration>

これにより、IISサーバーはメインページを404エラーの代わりにクライアントに返すようになり、ハッシュ履歴を使用する必要がなくなります。


ありがとう兄貴!!!!それは仕事です!
Thanh Bao

12

これを追加するwebpack.config.js

devServer: {
    historyApiFallback: true
}

これは開発者にとっては素晴らしいことですが、本番環境のビルドには役立ちません。
KFunk

11

生産スタック:React、React Router v4、BrowswerRouter、Express、Nginx

1)プリティURLのユーザーBrowserRouter

// app.js

import { BrowserRouter as Router } from 'react-router-dom'

const App = () {
  render() {
    return (
        <Router>
           // your routes here
        </Router>
    )
  }
}

2)を使用して、不明なすべてのリクエストにindex.htmlを追加します /*

// server.js

app.get('/*', function(req, res) {   
  res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
    if (err) {
      res.status(500).send(err)
    }
  })
})

3)webpackをバンドルする webpack -p

4)実行nodemon server.jsまたはnode server.js

編集:nginxにサーバーブロックでこれを処理させ、ステップ2を無視することができます:

location / {
    try_files $uri /index.html;
}

未定義のパスを取得
Goutham 2017

あなたのserver.jsファイルの追加のいずれかの上部に@Goutham import path from 'pathconst path = require('path')
アイザック・朴

ステップ2(すべてをでキャッチ/*)は私の日を救いました。ありがとうございました!:)
Atlas7

Reduxのを使用して、接続されたルータに関わる人々のためのこの作品は、この例を参照してください。github.com/supasate/connected-react-router/tree/master/examples/...
cjjenkinson

10

Create React Appを使用している場合:

あなたが見つけることができることを多くの主要なホスティング・プラットフォームのためのソリューションで、この問題のかかわらず、素晴らしい徒歩ありますHEREアプリページを反応させるの作成には。たとえば、フロントエンドコードにReact Router v4とNetlifyを使用しています。必要なのは、1つのファイルをパブリックフォルダー( "_redirects")に追加し、そのファイルに1行のコードを追加することだけです。

/*  /index.html  200

これで、私のウェブサイトは、ブラウザーに入力されたとき、または誰かが更新をヒットしたときに、mysite.com / pricingのようなパスを適切にレンダリングします。


7

以下のコードを使用して、パブリックフォルダー内に「.htaccess」ファイルを追加してみてください。

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]  

おかげで、これはFedora 28でApacheを使用して機能したものです。上記の書き換えルールも、CRAページのルールも、私にはうまくいきませんでした。個別の.htaccessファイルではなく、仮想ホスト設定に追加しました。
boerre

6

index.htmlへのフォールバックがある場合は、index.htmlファイルに次のことを確認してください。

<script>
  System.config({ baseURL: '/' });
</script>

これはプロジェクトごとに異なる場合があります。


2
これをhtmlに追加しますhead:<base href = "/">
Efe Ariaroo 2018

4

Firebaseを使用している場合は、アプリのルート(ホスティングセクション)のfirebase.jsonファイルにrewritesプロパティがあることを確認するだけです。

例えば:

{ 
  "hosting": {
    "rewrites": [{
      "source":"**",
      "destination": "/index.html"
    }]    
  }
}

これにより、他の誰かが欲求不満と時間の無駄を省くことができますように。

ハッピーコーディング...

主題についてさらに読む:

https://firebase.google.com/docs/hosting/full-config#rewrites

Firebase CLI:「単一ページアプリとして設定(すべてのURLを/index.htmlに書き換えます)」


あなたは伝説
です

4

私はSPAのソリューションを反応ルーター(Apache)で見つけました。.htaccessを追加するだけです

<IfModule mod_rewrite.c>

  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]

</IfModule>

ソース:https : //gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042


3

私はまだサーバー側レンダリングを使用していませんが、OPと同じ問題が発生しました。Linkはほとんどの場合正常に機能しているように見えましたが、パラメーターがあると失敗しました。私の解決策をここに文書化して、それが誰かに役立つかどうかを確認します。

私のメインのjsxにはこれが含まれています:

<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />

これは最初に一致したリンクでは正常に機能しますが、:idが <Link>そのモデルの詳細ページにネストされ式で変更されると、ブラウザーバーでURLが変更されますが、ページのコンテンツは最初はリンクモデルを反映するように変更されませんでした。

問題は、を使用しprops.params.idてでモデルを設定していたことcomponentDidMountです。コンポーネントは1回だけマウントされるため、これは最初のモデルがページに貼り付けられたモデルであり、後続のリンクはプロップを変更しますが、ページは変更せずに残します。

両方のコンポーネント状態におけるモデル設定componentDidMountとでcomponentWillReceiveProps(それは次の小道具に基づいている)問題を解決し、ページコンテンツは、所望のモデルを反映するように変更します。


1
サーバー側のレンダリングを試したい場合は、コンポーネントコンストラクター(にもアクセスできますprops)isoを使用componentDidMountすることをお勧めします。componentDidMountブラウザーでのみ呼び出されるためです。その目的は、DOMでは、イベントリスナーをにアタッチするbodyなど、実行できないことを行うことですrender
Stijn de Witt

3

このトピックは少し古く、解決されていますが、簡単で明確でより良いソリューションを提案したいと思います。Webサーバーを使用している場合に機能します。

各Webサーバーには、http 404の場合にユーザーをエラーページにリダイレクトする機能があります。この問題を解決するには、ユーザーをインデックスページにリダイレクトする必要があります。

Javaベースサーバー(tomcatまたは任意のJavaアプリケーションサーバー)を使用する場合、解決策は次のようになります。

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- WELCOME FILE LIST -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- ERROR PAGES DEFINITION -->
    <error-page>
        <error-code>404</error-code>
        <location>/index.jsp</location>
    </error-page>

</web-app>

例:

  • GET http://example.com/about
  • このページはサーバー側に存在しないため、Webサーバーはhttp 404をスローします
  • エラーページ構成は、index.jspページをユーザーに送り返すことをサーバーに伝えます。
  • クライアント側のURLがまだhttp://example.com/aboutであるため、JSはクライアント側で残りの作業を行います。

つまり、これ以上の魔法の必要はありません:)


これは最高でした!Wildfly 10.1サーバーを使用しており、場所を '/'に設定した以外は、この更新をweb.xmlファイルに加えました。:これは私の反応のコード私はこのようなブラウザの履歴を使用していたconst browserHistory = useRouterHistory(createHistory)({ basename: '/<appname>' });
チャック・L

1
これがSEOに影響を及ぼさないと確信していますか?あなたは実際に存在するページに404ステータスを与えています。ユーザーはこれに気付かない可能性がありますが、ボットは多くの注意を払っています。
subharb

3

バックエンドでExpressまたは他のフレームワークを使用している場合は、以下と同様の構成を追加して、構成内のWebpackパブリックパスをチェックアウトできます。BrowserRouterを使用している場合は、リロード時でも正常に機能します。

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});

これが最も簡単な解決策です。このルートは他のルートよりも後になるはずです。すべてをキャッチするためです
dcsan

3

更新時またはURLを直接呼び出すときの「GET / URLを実行できません」エラーを修正します。

与えられたリンクがこのようなルートになることを期待するようにwebpack.config.jsを設定します。

module.exports = {
  entry: './app/index.js',
  output: {
       path: path.join(__dirname, '/bundle'),
       filename: 'index_bundle.js',
       publicPath: '/'
  },

2

.Net Core MVCを使用しているので、次のようなものが役立ちました。

    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var url = Request.Path + Request.QueryString;
            return App(url);
        }

        [Route("App")]
        public IActionResult App(string url)
        {
            return View("/wwwroot/app/build/index.html");
        }
   }

基本的にMVC側では、一致しないすべてのルートがHome/Indexで指定されたとおりに分類されstartup.csます。内部Indexでは、元のリクエストURLを取得して、必要な場所に渡すことができます。

startup.cs

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });

Web APIがアプリから分離されている場合、これをどのように処理しますか?
dayanrr91

@ dayanrr91プロジェクトにWeb APIがある場合は、サーバー側のルーティングは必要ありません。そして、あなたの反応ルーターはURLを読んで適切なルーティングを行うべきだと思います。何もそれを妨げるべきではない
Elnoor

あなたのコメントは非常に高く評価されていますが、質問があります、HashRouterを追加しましたが、手動でURLに入力すると、ホームにリダイレクトされずに、ホームコンポーネントにリダイレクトされます。入ります、そのための回避策はありますか?
dayanrr91

@ dayanrr91本当にわからない、これまでhashrouterを試したことはありませんが、あなたのコードと何か関係があると思います。hashrouterの動作方法はbrowserrouterに似ています。また、私はこのサンドボックスでここでテストしたところ、それがうまく機能しますcodesandbox.io/s/25okp1mny、URL 25okp1mny.codesandbox.io/#/roster/5をテストします
Elnoor

2

IISでホストしている場合; これを私のwebconfigに追加すると問題が解決しました

<httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
    <remove statusCode="500" subStatusCode="100" />
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" path="/" responseMode="ExecuteURL" />
    <error statusCode="500" prefixLanguageFilePath="" path="/error_500.asp" responseMode="ExecuteURL" />
    <error statusCode="500" subStatusCode="100" path="/error_500.asp" responseMode="ExecuteURL" />
</httpErrors>

他のサーバーでも同様の構成を行うことができます


1

場合によっては、Laravelを使用したReact JS SPAのソリューションを探している人がいます。 受け入れられた答えは、そのような問題が発生する理由の最良の説明です。すでに説明したように、クライアント側とサーバー側の両方を構成する必要があります。ブレードテンプレートにjsバンドルファイルを含め、必ずURL facadeこのように使用してください

<script src="{{ URL::to('js/user/spa.js') }}"></script>

ルートでは、ブレードテンプレートがあるメインエンドポイントにこれを追加してください。例えば、

Route::get('/setting-alerts', function () {
   return view('user.set-alerts');
});

上記はブレードテンプレートの主なエンドポイントです。次に、オプションのルートも追加します。

Route::get('/setting-alerts/{spa?}', function () {
  return view('user.set-alerts');
});

発生する問題は、最初にブレードテンプレートがロードされ、次に反応ルーターがロードされることです。したがって、を'/setting-alerts'ロードするときは、htmlとjsがロードされます。ただし、をロードすると'/setting-alerts/about'、最初にサーバー側にロードされます。サーバー側ではこの場所に何もないため、not foundが返されます。オプションのルーターがある場合は、同じページが読み込まれ、反応ルーターも読み込まれ、反応ローダーが表示するコンポーネントを決定します。お役に立てれば。


サーバーに1つの正確なURIをロードして、サーバーがReactにリダイレクトすることは可能ですか?例のように、をロード/user/{userID}すると、ユニバーサル/userHTMLビューを返し、IDを取得して、AJAXまたはaxiosを使用して呼び出すだけです。それは可能ですか?彼らはSEOフレンドリーですか?
リュウジョ

1

IIS 10を使用している人にとって、これはこれを正しく行うためにすべきことです。これでb​​rowserHistoryを使用していることを確認してください。参考までに、ルーティングのコードを示しますが、これは重要ではありません。重要なのは、以下のコンポーネントコードの後の次のステップです。

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />    
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

問題はIISがクライアントブラウザからリクエストを受信することなので、URLをページを要求しているかのように解釈し、利用可能なページがないため404ページを返します。以下をせよ:

  1. IISを開く
  2. サーバーを展開し、サイトフォルダを開きます
  3. ウェブサイト/アプリケーションをクリックします
  4. エラーページに移動
  5. リストで404エラーステータスアイテムを開く
  6. 「静的ファイルからエラー応答にコンテンツを挿入する」オプションの代わりに、「このサイトでURLを実行する」に変更し、「/」スラッシュ値をURLに追加します。

そして、それは今うまく機能します。

ここに画像の説明を入力してください ここに画像の説明を入力してください

お役に立てば幸いです。:-)


1

WebPackを使用していますが、同じ問題が発生しましたSolution => server.jsファイル内

const express = require('express');
const app = express();

app.use(express.static(path.resolve(__dirname, '../dist')));
  app.get('*', function (req, res) {
    res.sendFile(path.resolve(__dirname, '../dist/index.html'));
    // res.end();
  });

更新後にアプリケーションがレンダリングされないのはなぜですか?


これでうまくいきました!最初はres.sendFile(path.JOIN(publicPath、 "index.html"));がありました。上記の例のように、 "join"を "resolved"に変更しました:res.sendFile(path.resolve( "./ dist"、 "index.html")); 私も__dirnameをいじっていましたが、実際には理解できなかったため、「./ dist」に手動でコピーしました。これが、index.htmlが提供される場所だからです。先ほどと同じように宣言しました:app.use(express.static( "./ dist"));
logixplayer

1

ReduxHashRouterで私のために働いた使用も、単に置き換えるだけです:

import {
  Router //replace Router
} from "react-router-dom";

ReactDOM.render(
    <LocaleProvider locale={enUS}>
    <Provider store={Store}>
        <Router history={history}> //replace here saying Router
            <Layout/>
        </Router>
    </Provider>
</LocaleProvider>, document.getElementById("app"));
registerServiceWorker();

に:

import {
  HashRouter //replaced with HashRouter
} from "react-router-dom";

ReactDOM.render(
    <LocaleProvider locale={enUS}>
    <Provider store={Store}>
        <HashRouter history={history}> //replaced with HashRouter
            <Layout/>
        </HashRouter>
    </Provider>
</LocaleProvider>, document.getElementById("app"));
registerServiceWorker();

0

私はこれと同じ問題を抱えており、この解決策は私たちにとってうまくいきました。

バックグラウンド:

同じサーバーで複数のアプリをホストしています。サーバーを更新すると、サーバーは特定のアプリのdistフォルダーでインデックスを探す場所を理解できません。上記のリンクをクリックすると、私たちにとって何が効果的であるかがわかります...私たちのニーズに対する解決策を考え出すためにかなりの時間を費やしてきたので、これが役に立てば幸いです。

私たちは使用しています:

package.json

"dependencies": {
"babel-polyfill": "^6.23.0",
"ejs": "^2.5.6",
"express": "^4.15.2",
"prop-types": "^15.5.6",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-persist": "^4.6.0",
"redux-thunk": "^2.2.0",
"webpack": "^2.4.1"
}

私のwebpack.config.js

webpack.config.js

/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const babelPolyfill = require('babel-polyfill');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/views/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    'babel-polyfill', './app/index.js'
  ],
  output: {
    path: __dirname + '/dist/your_app_name_here',
    filename: 'index_bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      query : {
          presets : ["env", "react", "stage-1"]
      },
      exclude: /node_modules/
    }]
  },
  plugins: [HTMLWebpackPluginConfig]
}

私のindex.js

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import Routes from './Routes'
import { Provider } from 'react-redux'
import { createHistory } from 'history'
import { useRouterHistory } from 'react-router'
import configureStore from './store/configureStore'
import { syncHistoryWithStore } from 'react-router-redux'
import { persistStore } from 'redux-persist'

const store = configureStore();

const browserHistory = useRouterHistory(createHistory) ({
  basename: '/your_app_name_here'
})
const history = syncHistoryWithStore(browserHistory, store)

persistStore(store, {blacklist: ['routing']}, () => {
  console.log('rehydration complete')
})
// persistStore(store).purge()


ReactDOM.render(
    <Provider store={store}>
      <div>
        <Routes history={history} />
      </div>
    </Provider>,
  document.getElementById('mount')
)

私のapp.js

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/dist'));
// app.use(express.static(__dirname + '/app/assets'));
app.set('views', __dirname + '/dist/your_app_name_here');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

app.get('/*', function (req, res) {
    res.render('index');
});

app.listen(8081, function () {
  console.log('MD listening on port 8081!');
});

0

私はそれを扱うこの方法が好きです。サーバー側にyourSPAPageRoute / *を追加して、この問題を解消してください 。

(私が知る限り)ネイティブHTML5 History APIでもページ更新時の正しいリダイレクトをサポートしていないため、このアプローチを採用しました。

注:選択された回答はすでにこれに対処していますが、より具体的になるように努めています。

エクスプレスルート

テスト-履歴API テスト済みで、これを共有したかっただけです。

それが役に立てば幸い。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.