Firebase托管的单页应用程序中深度路由出现问题

13

(以下内容稍作更新)

我们有一个基于React的单页Web应用程序,托管在Firebase Hosting上。到目前为止,我们一直使用哈希路由(例如mysite.com/#/path/to/content)。我们引入了React Router,这使我们可以拥有更美观的URL(例如mysite.com/path/to/content),但现在当我们直接导航到深层路径时,应用程序不会加载。详细信息如下:

使用React Router需要在Firebase Hosting中使用URL重写。指南非常简单 - 似乎你所需要做的就是这样:

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

...在firebase.json文件中。事实上,我们完整的firebase.json文件如下所示:

{
"firebase": "",
"public": "dist",
"rules": "rules.json",
"ignore": [
    "firebase.json",
    "**/.*",
    "**/*.map",
    "**/node_modules/**"
],
"rewrites": [ 
    {
    "source": "**",
    "destination": "/index.html"
    }
]
}

这里没有太复杂的内容(如果您想知道为什么firebase参数为空,我们正在构建脚本中执行firebase deploy -f)。链接到rules.json文件甚至更简单:

{
   "rules":{
   ".write":"true",
   ".read":"true"
 }
}

当我通过访问基本URL加载应用并开始导航时,一切正常。如果我直接进入一个一级路由(例如mysite.com/path),那也没问题。

然而

如果我直接进入深层级的路由,甚至是带有尾随斜杠的顶级路由(例如mysite.com/path/mysite.com/path/to/content),则该应用程序不会加载。

具体来说,发生了以下情况:网页首先加载index.html页面,然后浏览器试图加载在index.html中引用的我们webpack创建的bundle.js文件,但Firebase Hosting返回的JS文件内容却是index.html文件的内容。因此,可预见的是,我们在浏览器控制台中看到了这个错误:

Uncaught SyntaxError: Unexpected token <

...位于“捆绑文件”的第1行。如果我在Chrome的开发工具中查看捆绑文件的内容,则捆绑文件的第1行实际上是:

<!doctype html>

...然后是index.html文件的其余部分。

似乎Firebase URL重写规则正在说“哦,你正在尝试引用JS文件——我看到我应该为所有内容返回index.html文件的内容,所以给你”。但如果情况总是这样,那么该站点在任何情况下都将无法正常工作。所以,为什么如果我从站点根目录开始,它能工作,但如果我粘贴一个深度URL到应用程序中,就会出现错误呢?我一点都不知道。

如果有帮助的话,这是我index.html文件如何引用bundle文件的方式:

<script src="bundle.ce843ef7a2ae68e9e319.js"></script></body>

看起来这是Firebase托管的问题,但我也可能在某种程度上不理解React Router,因此我已经通过某种方式在客户端代码中弄错了事情,以致它迫使服务器返回错误的内容。

我希望这只是一些我们遗漏的愚蠢配置。任何帮助都将不胜感激!

谢谢!

更新:我简化了我们的应用程序,所以它仅返回“hello, world”,这将绕过所有基于React的东西,包括React Router,并且问题仍然存在,因此我不再认为这与React-Router有关,虽然我认为还是有一小部分可能与React有关。

4个回答

14

我从 Firebase Hosting 那里得到了回复。显然,我们在索引文件中引用的 bundle.js 文件需要在其前面加上一个斜杠,以使它成为绝对路径。所以原来的代码是这样的:

<script src="/bundle.js"></script>

不要使用这个:

<script src="bundle.js"></script>

如果其他人也犯了同样的愚蠢错误,我希望这会有所帮助。


谢谢!我也遇到了同样的问题,请记住这也会影响CSS文件的引用,你需要在那些地方加上 /。 - Roberto
@hairbo:谢谢B,从没想过在StackOverflow上会遇到一位老同事,更不用说得到他的帮助了!这个答案对我的一个副业项目很有帮助。 - Ezra Chang
不错!很高兴听到这个消息,Ezra!希望一切都好。 - hairbo
1
太棒了,这是我疏忽了的地方,这里有一个很好的解释。谢谢。因为OP提到了React,我想提一下,对于我来说,webpack生产配置需要一个output: {publicPath: '/'} - Priya Ranjan Singh
1
这太不可思议了!我在这里看了三个小时,查看每个配置项,结果只是一个斜杠问题。我有点紧张和开心的感觉。 - Victor Leal
它对我没有解决。我的webpack-dev-server正在提供正确的行为。但是使用根相对路径并没有为我解决同样的问题。 - sn.anurag

3
我遇到了相同的问题,但问题与 bundle.js 无关。
我的 firebase.json 文件中的 rewrites 部分如下所示:
    "rewrites": [
      {
        "source": "**",
        "destination": "index.html"
      }
    ]

我通过使用根相对路径而不是index.html相对路径来解决了问题。(感谢Ashu!)

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

2

[简述]

本答案仅供教育目的,深入探讨问题陈述及其解决方案。如需复制/粘贴,请参见@hairbo提供的此答案。它是简短版本,并简单明了地回答了问题。

所有指向图片、CSS、JS等资源的链接都可以通过以下3种方式引用:

1)绝对路径

<script src="http://app-url.com/bundle.js"></script>

这是绝对路径,资源将从指定路径加载,不会预处理提供的路径。

2) 相对路径

<script src="bundle.js"></script>

这是相对路径,它将资源文件视为位于当前工作目录中。例如,在app-url.com/lvl-1时,相对路径变成了app-url.com/bundle.js,这没有问题,因为这实际上是资源的路径。 问题 但是当进一步深入到另一个级别,即app-url.com/lvl-1/lvl-2时,当前工作级别变成了app-url.com/lvl-1/,相对路径被视为app-url.com/lvl-1/bundle.js,但这实际上不是资源的路径。因此,index.html文件无法加载所需的文件。 3) 根相对路径
<script src="/bundle.js"></script>

在相对路径前添加斜杠(/)会使其成为根相对路径。在这种情况下,所有非绝对路径都被视为以当前域为根路径的路径。也就是说,在这种情况下,资源路径/bundle.js被视为app-url.com/bundle.js,即使当前工作级别的url是app-url/lvl-1/lvl-2/lvl-3/...解决方案 不要使用~相对路径~。在所有文件中使用绝对路径或根相对路径。这样每个路径都会按预期处理。

1
我曾经遇到过同样的问题,我通过在firebase.json文件中添加重写规则来解决它。
下面是我的firebase.json文件的样子。
    {
  "hosting": {
    "public": "webApp/build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "cleanUrls": true,
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
  "functions": {    
    "source": "functions"
  }
}

抱歉我的英语不好,我还在学习。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接