使用 Express 的单页应用程序 React 路由 URL。但不要使用 create-react-app 或 Heroku 之类的部署服务

Posted

技术标签:

【中文标题】使用 Express 的单页应用程序 React 路由 URL。但不要使用 create-react-app 或 Heroku 之类的部署服务【英文标题】:single-page-application React route URLs using Express. But NOT using create-react-app or deployment services like Heroku 【发布时间】:2019-05-21 22:25:57 【问题描述】:

我的问题很常见:​​我有一个单页 React 应用程序,一切正常,但如果直接导航或刷新 URL 子页面将无法加载。

我花了几个小时(也许几天)搜索,许多论坛帖子/文章/教程写的关于这个问题的前提是使用像 Heroku 或 Digital Ocean 这样的部署平台,它们要么为你做一些工作,要么可能有一些混淆了我无法解析的相关工作,以使其对我的特定应用程序有意义。

不涉及特殊部署平台的讨论总是假设我使用 create-react-app 创建了我的应用程序,但我没有。我试图在 create-react-app 中重新创建使单页应用程序路由正常工作的进程(npm build 被编程为使 nodepackages/react-scripts/bin 运行 react-scripts.js,但 react-scripts 中的代码。 Node.js 比我的技能水平高一点,而且似乎还涉及 create-react-app 的其他方面——再说一次,我没有使用过——所以我放弃了。)

在开始这个过程之前,我对后端编程知之甚少。现在我参加了关于 node.js 和 MongoDB 的课程(我现在意识到 Mongo 与我正在尝试做的事情完全无关)。我目前正在参加 Express 课程,但我仍然有点出海,我几乎可以肯定有一个非常简单的解决方案。

我希望有人可以:a)解释我缺少什么; b) 将我引导到可以解释但不使用特殊部署平台或 create-react 应用程序的来源;或 c) 只需告诉我我缺少的一两行代码(我很确定它最终只会是一两行)。

我使用 Gulp 作为我的任务运行器构建了我的网站,并且一切都在本地运行良好(例如,刷新并直接访问像 localhost:3000/about 这样的子页面 URL 有效)。

负责这个的 Gulpfile 代码是:

const browserSync = require('browser-sync');
const historyApiFallback = require('connect-history-api-fallback');

function bs() 
    browserSync.init(
        server: 
            baseDir: './'
        ,
        middleware: [historyApiFallback()]
    )
;

您可能很明显——这是我的设置——当简单地将站点文件夹上传到 cPanel 文件主机并期望它像在本地一样工作时,尝试通过 URL 直接访问 React 路由将停止工作,但那时我并不知道更好。

我现在正在尝试使用 Express 来设置我的 server.js 文件,以使单页应用程序路由工作。我已经告诉节点在我的 package.json 中运行 server.js。这是我的 server.js 文件的样子:

var express = require('express')
var path = require('path')
var history = require('connect-history-api-fallback');

var app = express()

app.use(history());

app.use(express.static(__dirname))

app.get('*', function (req, res) 

     // I've fiddled with this part a million 
    //different ways but can't seem to get it to work 
    //because including lines like 'alert('WORKING') or 
    //res.alert('WORKING') in here never result in an alert 
    //pop-up when entering a URL

     res.sendFile(path.join(__dirname, '/index.html'))
)

var PORT = process.envPORT || 8080
app.listen(PORT, function() 
    console.log('Production Express server running at localhost: ' + PORT)
)

最终我希望像 www.mysite.com/about/ 这样的 URL 从我的 React 路由器加载页面和“/about”路由,但此时我会满足于任何和所有直接 URL 请求只转发到www.mysite.com/index,我也尝试过但失败了。

也许最好像在和孩子说话一样说出你的答案。

【问题讨论】:

【参考方案1】:

你现在找错地方了。请记住,React 是用户和浏览器之间的接口(除了您的内容分发网络 (cdn),但我们目前对此不感兴趣)。您的服务器与浏览器交互(React)。不是用户。您的快速服务器用于向您的 SPA 提供数据。路由由 React 控制。

正如您所发现的,直接路由不起作用,因为从技术上讲,您的网站只有一个 index.html 文件供 React 捎带。这意味着两件事:

    React 必须能够解释不同的路由 指向您的域的每个可能的 url 都必须直接访问 index.html

带有react-router的SPA路由

对于第一个问题,您需要明确的路由逻辑。这就是 npm 包 react-router 的用途。

修改您的域名托管服务商设置,使其始终指向index.html,无论用户输入什么网址

其次,您必须设置您的域名托管服务商以正确路由。如果您访问除index.html 以外的任何内容,您将获得404。您可以利用这一点并设置您的主机将404 直接重定向到index.html。这有点老套,但事情就是这样完成的(除了哈希历史,我们可以稍后再讨论)。

绕过主机配置,只需要react-router,使用hashHistory

如果您想回避主机配置修改,可以使用react-routerhashHistory 而不是browserHistory。它在您的域和任何其他路由之间创建/#/,这使您可以回避index.html404 路由。这样做的缺点是你会得到“丑陋”的网址。

my-website.com/#/a_route

my-website.com/#/another_route

祝你好运

【讨论】:

如果解决方案位于 react-router npm 包中,那么这将是一个真正的绿野仙踪,结束我的旅程......我确实在我的项目中使用了 react-router 包(实际上我使用了react-router-dom,但我的理解是它完成了 react-router 所做的一切。来源:github.com/ReactTraining/react-router/issues/…)。 npmjs.com 上这两个包的官方文档非常少。我知道我可以使用哈希,但正如你所说,它很难看。没有他们我不知道该怎么做,这也很可耻。 我会考虑设置我的域名托管服务商设置以将所有请求重定向到 index.html ...除非您有其他关于如何制作/学习使路由 URL 正常工作的提示? 据我所知,仅使用 react-router 而不使用 hashHistory 是不可能的。您的网站基本上没有多个页面。一切都必须运行index.html

以上是关于使用 Express 的单页应用程序 React 路由 URL。但不要使用 create-react-app 或 Heroku 之类的部署服务的主要内容,如果未能解决你的问题,请参考以下文章

React 路由与 Express 路由

使用的vueelementUIvuexexpressmongoDB的单页应用

基于react-router的单页应用

基于react-router的单页应用

React在哪里放置一个带有侧边菜单的单页应用程序的登录页面

使用服务器端和客户端渲染的单页 ReactJS 应用程序?