React Routing 在本地机器上工作,但在 Heroku 上不工作

IT技术 javascript reactjs heroku react-router
2021-02-09 01:15:09

React/react router/heroku 问题在这里(它可能是 heroku 失败的地方)。

我正在关注这个精彩的教程:https : //medium.com/@patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d#.y77yjte2j 一切正常,直到我发布为止它到 heroku,我尝试导航到https://appname.herokuapp.com/about,我收到 404 Not Found/nginx 错误。当然,根据教程,它应该显示一个关于页面。

底线:React 路由器在 heroku 上不起作用,我不知道为什么.

我尝试server/app.js按照以下建议修改我的文件:React 路由在 facebook 的 create-react-app 构建中不起作用

// server/app.js
const express = require('express');
const morgan = require('morgan');
const path = require('path');

const app = express();

console.log('hi from /src/server.js')
// Setup logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));

// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));

// Always return the main index.html, so react-router render the route in the client

app.get('/about', (req, res) => {

  console.log('hi from app.get.about')
  console.log(req)
  console.log(res)
  res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
app.get('/*', (req, res) => {

  console.log('hi from app.get')
  console.log(req)
  console.log(res)
  res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});


module.exports = app;

但它不起作用,也不会在控制台中记录任何内容:

2017-01-20T21:03:47.438140+00:00 heroku[web.1]: Starting process with command `bin/boot`
2017-01-20T21:03:49.540005+00:00 app[web.1]: Injecting runtime env into /app/build/static/js/main.242e967b.js (from .profile.d/inject_react_app_env.sh)
2017-01-20T21:03:49.695317+00:00 app[web.1]: Starting log redirection...
2017-01-20T21:03:49.695899+00:00 app[web.1]: Starting nginx...
2017-01-20T21:03:51.108255+00:00 heroku[web.1]: State changed from starting to up
2017-01-20T21:04:22.720627+00:00 heroku[router]: at=info method=GET path="/" host=sentieoapp1.herokuapp.com request_id=fb8bc13b-f6b5-47bc-8330-443f28e211df fwd="132.147.73.97" dyno=web.1 connect=0ms service=3ms status=200 bytes=627
2017-01-20T21:04:22.746761+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:22 +0000] "GET / HTTP/1.1" 200 386 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
2017-01-20T21:04:23.076521+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:23 +0000] "GET /static/js/main.242e967b.js HTTP/1.1" 200 62263 "https://sentieoapp1.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
2017-01-20T21:04:23.056416+00:00 heroku[router]: at=info method=GET path="/static/js/main.242e967b.js" host=sentieoapp1.herokuapp.com request_id=436d5ce5-ee39-4ab7-9e12-f5871e0fd552 fwd="132.147.73.97" dyno=web.1 connect=0ms service=25ms status=200 bytes=62540
2017-01-20T21:04:23.745285+00:00 heroku[router]: at=info method=GET path="/static/css/main.9a0fe4f1.css" host=sentieoapp1.herokuapp.com request_id=80438aaa-58c4-456e-8df9-7a29e49bc4ba fwd="132.147.73.97" dyno=web.1 connect=0ms service=2ms status=200 bytes=560
2017-01-20T21:04:23.766676+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:23 +0000] "GET /static/css/main.9a0fe4f1.css HTTP/1.1" 200 301 "https://sentieoapp1.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
2017-01-20T21:04:24.044940+00:00 heroku[router]: at=info method=GET path="/static/media/logo.5d5d9eef.svg" host=sentieoapp1.herokuapp.com request_id=bcbc1906-3b90-4f13-a700-f432f79c725d fwd="132.147.73.97" dyno=web.1 connect=0ms service=1ms status=200 bytes=2902
2017-01-20T21:04:24.065013+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:24 +0000] "GET /static/media/logo.5d5d9eef.svg HTTP/1.1" 200 2671 "https://sentieoapp1.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
2017-01-20T21:04:26.264631+00:00 heroku[router]: at=info method=GET path="/about" host=sentieoapp1.herokuapp.com request_id=0caef324-9268-4ebb-a3f5-0fb047100893 fwd="132.147.73.97" dyno=web.1 connect=0ms service=4ms status=404 bytes=403
2017-01-20T21:04:26.284717+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:26 +0000] "GET /about HTTP/1.1" 404 191 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"

这就是我被困的地方。我熟悉 Express 并且之前已经让它在 heroku 上工作,但这完全是另一个级别的噩梦。我知道这不是服务器端路由,而是从单个 index.html 页面内进行路由的react。但是如果我可以让它在我的本地机器上工作,为什么它不能在 Heroku 上工作?

4个回答

实际上,我在搜索 react-router 和 heroku 文档的 3 个小时之前首先看到了这篇文章。对于 swyx 和其他任何有同样问题的人,我将概述您需要做什么才能使其正常工作。

router.js - (显然将 AppSplash 和 AppDemo 更改为您的组件)

export default <Router history={hashHistory}>
  <Route path="/" component={App}>
    <IndexRoute component={AppSplash}/>
    <Route path="demo" component={AppDemo}/>
  </Route>
</Router>

应用程序.js

import React, { Component } from 'react'

class App extends Component {
static propTypes = {
  children: PropTypes.node
}

render() {
  const { children } = this.props
  return (
    <div>
      {children}
    </div>
  )
}
}

export default App

在您的主目录的根目录中创建一个新文件并将其命名为static.json把这个放进去

{
  "root": "build/",
  "clean_urls": false,
  "routes": {
    "/**": "index.html"
  }
}

再次推送到heroku。这次路线应该可以工作了。

解释:

您需要修改 Heroku 的默认 webpack,否则服务会与如何处理客户端路由混淆。本质上是 static.json 做什么。其余的只是根据“react-router”文档处理路由的正确方法。

该解决方案适用于 GitHub 页面吗?我已经被屏蔽两天了... stackoverflow.com/questions/49045867/ ...
2021-03-14 01:15:09
对我来说这不起作用,我在stackoverflow.com/questions/52852877/...
2021-03-17 01:15:09
仅供参考,这对我根本不起作用。添加的static.json效果为零。dhahn 的答案可以预见地有效,因为它确保 express 为不匹配任何 express 路由的 react-router URL 提供索引文件。
2021-03-17 01:15:09
哇,谢谢 HarshMarshmallow。这实际上可能使 create-react-app 对我有用,因为我可以在其上放置 react 路由器。自从我问这个问题以来,我已经完全放弃了这条路线,并寻找了其他完全可部署的样板。无需测试即可标记您正确
2021-03-23 01:15:09

如何修复客户端路由错误(Heroku 404 错误):

react浏览器路由器

如果您使用React Browser Router作为带有create-react-appnpmmodule,那么解决方案(对我有用)是创建一个文件(在与 相同的目录中)。static.jsonpackage.json

{
  "root": "build/",
  "clean_urls": false,
  "routes": {
    "/**": "index.html"
  }
}

这就是此解决方案有效的原因:

Create-react-app大部分是一个Node.Js服务器,它为客户端React提供服务public静态目录映射到/端点,并从浏览器访问该终端将下载的index.html网页。该网页依次加载 React 组件。并且因为React Browser Router是一个 React 组件,路由在访问/端点后动态加载换句话说,在index.html网页加载之前,我们所有的React Browser Router路由都会在 Heroku 上导致 404 错误。要解决此问题,static.json可以使用文件将具有以下模式的任何端点映射/**index.html 文件,它将加载 React Browser Router 并正确加载该路由的 react 组件。

从 Apache HTTP 服务器:

同样,在 Apache HTTP 服务器上.htaccess,在public目录中创建文件,将重新映射与/**index.html文件匹配的所有端点

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

更多资源

另请阅读create-react-app自述文件的“部署”部分,其中包含大量关于如何重新配置​​服务器以使用客户端路由的好信息。

https://facebook.github.io/create-react-app/docs/deployment

react静态路由器

最后,React Router提供了一个静态路由器React Static Router,它可以与Node.js 服务器上的“react-dom/server” npmmodule一起使用,以呈现JSX服务器端,并且不需要static.json.htaccess重新配置。

对于 IIS/Windows/Azure 服务器,这个 tut 是一个很好的帮助。medium.com/@to_pe/...
2021-03-15 01:15:09
@NullisTrue - facebook.github.io/create-react-app/docs/... - 可能有解决方案?
2021-03-28 01:15:09
这解决了我的问题谢谢你的信息
2021-04-02 01:15:09
@AnimeshSingh - facebook.github.io/create-react-app/docs/... - 还分享了一些其他链接,用于自动部署到 Azure
2021-04-08 01:15:09
@tfmontague 该解决方案适用于 GitHub 页面吗?我已经被屏蔽两天了... stackoverflow.com/questions/49045867/ ...
2021-04-12 01:15:09

试试这个:

app.get("*", (req, res) => {
  let url = path.join(__dirname, '../client/build', 'index.html');
  if (!url.startsWith('/app/')) // since we're on local windows
    url = url.substring(1);
  res.sendFile(url);
});

当我放入 server.js 时为我工作。

这对我有用,但前提是确保我index.html在某些情况下不会返回,例如请求transformed.js. 我写了一个更详细的解释作为单独的帖子。谢谢!
2021-03-16 01:15:09

Webpack+Express 方案

TL; 博士

使用res.sendFile但不要忘记还返回transformed.js和其他静态文件。

说明

我一直在测试这个线程上的一些答案,但没有一个真正适用于以下设置:

  • 我在本地机器上使用 webpack (-dev-server)。
  • 在生产中(在 Heroku 上),我只是使用静态快速服务器为 webpack 构建输出提供服务。类似的东西app.use(express.static('${__dirname}/build'));

这显然不适用于react-router,因为static仅从文件build夹(即index.html返回实际文件,并将在任何其他 url 上返回 404。

David Hahn 提出的使用解决方案为res.sendFile我指明了正确的方向。然而,劫持的主要问题GET *是第二个请求transformed.js也会返回index.html. 在修复代码以避免这种情况后,我能够得到一个可行的解决方案。

代码

这是我的server.js

const express = require("express");

const port = process.env.PORT || 8080;
var app = express();

// List of all the files that should be served as-is
let protected = ['transformed.js', 'main.css', 'favicon.ico']

app.get("*", (req, res) => {

  let path = req.params['0'].substring(1)

  if (protected.includes(path)) {
    // Return the actual file
    res.sendFile(`${__dirname}/build/${path}`);
  } else {
    // Otherwise, redirect to /build/index.html
    res.sendFile(`${__dirname}/build/index.html`);
  }
});

app.listen(port, () => {
  console.log(`Server is up on port ${port}`);
});

很高兴讨论您的想法!我还不是 React 老手,所以可能有更好的方法。干杯!