在这里发生反应/反应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 routes are not working in facebook's create-react-app build
// 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页面内做出路由。但是,如果我可以让它在我的本地机器上工作,为什么它不适用于Heroku?
答案 0 :(得分:37)
我实际上在通过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>
<强> app.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'文档处理路由的正确方法。
答案 1 :(得分:23)
如果你正在使用React Browser Router,作为带有 create-react-app 的 npm 模块,那么解决方案(适用于我)就是创建一个static.json
文件(与package.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路由器路由都会在Heroku上导致404错误。要解决此问题,可以使用static.json
文件将具有以下模式/**
的任何端点映射到index.html
文件,从而加载React Browser路由器并正确加载反应该路线的组成部分。
来自Apache HTTP服务器:
同样,在Apache HTTP服务器上创建.htaccess
目录中的public
文件时,会将所有与/**
匹配的端点重新映射到index.html
文件。
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
更多资源
另请阅读create-react-app
README的“部署”部分,其中包含有关如何重新配置服务器以使用客户端路由的大量信息。
https://facebook.github.io/create-react-app/docs/deployment
最后, React Router 提供了一个静态路由器React Static Router,它可以与节点上的“react-dom / server” npm 模块一起使用.js服务器,用于呈现 JSX 服务器端,不需要static.json
或.htaccess
重新配置。
答案 2 :(得分:1)
使用res.sendFile
,但不要忘记还返回transformed.js
和其他静态文件。
我已经在此线程上测试了一些答案,但是在以下设置中,没有一个真正起作用:
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的资深人士,所以可能会有更好的方法。干杯!
答案 3 :(得分:0)
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时为我工作。