React Router 无法在本地主机和远程主机上配置 URL。收到 404 not found 错误

React Router can't configure URLs on localhost and remote. Receiving 404 not found error

我遇到过奇怪的情况。我认为这个问题与 React Router V4 配置有关。

我正在使用 react-router-modalReact Router v4。使用 react-router-modal 组件,我将 link 渲染为模态 window,它有自己独特的 URL。单击模态框的 link 后,模态框将打开,并且 URL 将添加到地址栏。因此,我什至可以使用 url:http://localhost:8080/modal_1URL 从新选项卡访问模态 window,这对我来说非常重要。

在开发模式下(npm start)一切正常,一旦输入无效的URL,页面就会重新加载,无效的URL将保留在地址栏中。 (不是最好的情况)

我认为一切都会像在生产版本中一样工作。但是这里有一个问题。将最终版本上传到远程服务器或本地主机后,我收到以下错误:
1. 一旦输入无效 URL - 我收到 404 Not Found
2. 一旦我尝试使用直接 URL 访问模式(未在加载页面中单击)http://localhost:8080/modal_1 - 404 Not Found

没有上传.htaccess

index.js非常简单,整个应用程序只有一个页面,包含各种组件:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { ModalContainer } from 'react-router-modal';
import LandingPage from './components/villages/Landing Page.js';
import WOW from 'wowjs';

import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';

class App extends React.Component {
  componentDidMount() {
    new WOW.WOW().init();
  }

  render() {
    return (
      <div>
        <LandingPage />        
      </div>
    )
  }
}

ReactDOM.render(
  <I18nextProvider i18n={i18n}>
    <BrowserRouter>
      <div>
        <App />
        <ModalContainer />
      </div>
    </BrowserRouter>
  </I18nextProvider>,
  document.getElementById('app')
);

并且组件 呈现模态看起来像:

import React from 'react';
import ReactDOM from 'react-dom';
import { ModalRoute, ModalLink } from 'react-router-modal';
import { Link } from 'react-router-dom';
import ImageLoader from 'react-load-image';

function Preloader(props) {
  return <img src="img/spinner.gif" className="img-responsive center-block image-loader" />;
}

function ModalOne(props) {
  const { t } = props;
  return (
    <div className='basic__modal-content'>
    ...
    </div>
  );
}
const ExtendedModalOne = translate()(ModalOne);


class Items extends React.Component {

  render() {
    const { t } = this.props;
    return (
      <div className="container">
        <ul>
          <div id="works">
            <li>
              <Link to="/modal_1"> <img src="img/" /> </Link>
              <h3>Name</h3>
            </li>
          </div>
        </ul>
        <ModalLink component={ExtendedModalOne} path={`/modal_1`} />
        <ModalLink component={ExtendedModalTwo} path={`/modal_2`} />        
      </div>
    )
  }
}

module.exports = translate()(Items);

webpack.config:

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const StyleExtHtmlWebpackPlugin = require('style-ext-html-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const autoprefixer = require('autoprefixer');

const staticSourcePath = path.join(__dirname, 'css');
const sourcePath = path.join(__dirname);
const buildPath = path.join(__dirname, 'dist');

module.exports = {
    stats: {
    warnings: false
},
    devtool: 'cheap-module-source-map',
      devServer: {    
      historyApiFallback: true,
      contentBase: './'
  },
    entry: {
        app: path.resolve(sourcePath, 'index.js')
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].[chunkhash].js',
        publicPath: '/'
    },
    resolve: {
        extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js', '.jsx'],
        modules: [
            sourcePath,
            path.resolve(__dirname, 'node_modules')
        ]
    },
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production')
        }),
        new webpack.optimize.ModuleConcatenationPlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            filename: 'vendor.[chunkhash].js',
            minChunks (module) {
                return module.context && module.context.indexOf('node_modules') >= 0;
            }
        }),
        new webpack.LoaderOptionsPlugin({
            options: {
                postcss: [
                    autoprefixer({
                        browsers: [
                            'last 3 version',
                            'ie >= 10'
                        ]
                    })
                ],
                context: staticSourcePath
            }
        }),
        new webpack.HashedModuleIdsPlugin(),
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'index.html'),
            path: buildPath,
            excludeChunks: ['base'],
            filename: 'index.html',
            minify: {
                collapseWhitespace: true,
                collapseInlineTagWhitespace: true,
                removeComments: true,
                removeRedundantAttributes: true
            }
        }),
        new PreloadWebpackPlugin({
            rel: 'preload',
            as: 'script',
            include: 'all',
            fileBlacklist: [/\.(css|map)$/, /base?.+/]
        }),
        new webpack.NoEmitOnErrorsPlugin(),
        new CompressionPlugin({
            asset: '[path].gz[query]',
            algorithm: 'gzip',
            test: /\.js$|\.css$|\.html$|\.eot?.+$|\.ttf?.+$|\.woff?.+$|\.svg?.+$/,
            threshold: 10240,
            minRatio: 0.8
        })
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['env', 'react']
                  }
                },
                include: sourcePath
            },
            {
                test: /\.(eot?.+|svg?.+|ttf?.+|otf?.+|woff?.+|woff2?.+)$/,
                use: 'file-loader?name=assets/[name]-[hash].[ext]'
            },
            {
                test: /\.(png|gif|jpg|svg)$/,
                use: [
                    'url-loader?limit=20480&name=assets/[name]-[hash].[ext]'
                ],
                include: staticSourcePath
            }
        ]
    }
}; 

您的 HTTP 服务器应始终为任何路由发送 index.html 文件。

示例 NodeJS Express 配置:

// ...
const app = express();

app.get('*', (req, res) => {
  res.sendFile('path/to/your/index.html')
})

// ...

据我所知,对于 Apache 服务器,您可以使用:

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

它告诉 Apache 服务器将所有内容重写到 index.html 页面文件并让客户端处理路由。