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

Posted

技术标签:

【中文标题】Firebase 托管单页应用程序上的深度路由问题【英文标题】:Trouble with deep routes on a single-page app on Firebase hosting 【发布时间】:2016-05-29 20:57:00 【问题描述】:

(在下面更新了更多信息)

我们有一个基于 React 的单页网络应用,它存在于 Firebase 托管上。到目前为止,我们一直在使用基于哈希的路由(例如 mysite.com/#/path/to/content)。我们引入了 React Router,它允许我们拥有更漂亮的 URL(例如 mysite.com/path/to/content),但是现在当我们直接导航到深层路由时应用程序不会加载。详情如下:

使用 React Router 要求我们在 Firebase 托管中使用 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 托管为该 JS 文件返回的是 index.html 文件的内容。那么,可以预见的是,我们在浏览器控制台中看到的是这个错误:

Uncaught SyntaxError: Unexpected token <

...在“捆绑文件”的第 1 行。如果我在 Chrome 的开发工具中查看包文件的内容,包文件的第 1 行字面意思是这样的:

<!doctype html>

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

似乎发生了什么是 Firebase URL 重写规则说“哦,你正在尝试引用一个 JS 文件——我知道我应该为所有内容返回 index.html 的内容,所以在这里你走”。但这不可能一直如此,否则该网站在任何情况下都无法正常工作。那么,如果我从站点根目录开始,为什么它会起作用,但如果我将深层 URL 粘贴到应用程序,它会中断呢?我的想法为零。

如果有帮助,以下是我的 index.html 文件引用捆绑文件的方式:

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

所以这似乎是 Firebase 托管的问题,但我也可以看到,也许我在某种程度上不了解 React Router,所以我以某种方式将客户端代码搞砸了它迫使服务器返回错误的东西。

我希望这是我们缺少的一些愚蠢的配置。任何帮助表示赞赏!

谢谢!

更新:我剥离了我们的应用程序,使其只返回“hello,world”,它绕过了所有基于 React 的东西,包括 React 路由器,问题仍然存在,所以我不再认为这有任何关系使用 React-Router,尽管我认为这可能与 React 有关。

【问题讨论】:

【参考方案1】:

我收到了 Firebase Hosting 的回复。显然,我们索引文件中引用的 bundle.js 文件前面需要一个斜杠,以使其成为绝对路径。所以这个:

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

...而不是这个:

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

以防其他人犯同样的愚蠢错误,我希望这很有用。

【讨论】:

谢谢!我遇到了同样的问题,请记住这也会影响 CSS 文件引用,您也需要 / 。 @hairbo:谢谢 B,从没想过我会在 *** 上看到一位老同事,更不用说得到帮助了!这个答案帮助我完成了一个业余项目。 不错!很高兴听到这个消息,以斯拉!希望一切都好。 很棒的东西,我的疏忽和这里的一个很好的解释。谢谢。因为 OP 谈到了 react,所以我想提一下 webpack 生产配置需要一个 output: publicPath: '/' 对我来说。 这太不可思议了!我在这里待了 3 个小时,查看每个配置项,这是一个斜线。我既紧张又高兴【参考方案2】:

[tl;dr]

此答案仅用于教育目的和深入了解 问题陈述及其解决方案。对于复制/粘贴目的,请参阅 this answer provided by @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/...

解决方案不要使用~相对路径~。在所有文件中使用绝对路径或根相对路径。这样每条路径都会被处理 正如预期的那样。

【讨论】:

【参考方案3】:

我遇到了同样的问题,我修复了将重写规则添加到我的 firebase.json 文件的问题。

这是我的 firebase.json 文件的外观。

    
  "hosting": 
    "public": "webApp/build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "cleanUrls": true,
    "rewrites": [
      
        "source": "**",
        "destination": "/index.html"
      
    ]
  ,
  "functions":     
    "source": "functions"
  

对不起我的英语,我还在学习。

【讨论】:

【参考方案4】:

我遇到了同样的行为,但问题与bundle.js 无关。

firebase.jsonrewrites 部分看起来像这样:

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

我通过使用 root relative path 而不是 index.htmlrelative path 解决了这个问题。 (谢谢阿舒!)

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

【讨论】:

以上是关于Firebase 托管单页应用程序上的深度路由问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Firebase 托管为 React SPA 提供 404 页面?

如何使用 Firebase 为单页应用程序实现 sitemap.xml 文件?

为动态链接设置自定义路由,而不使用 Firebase 托管

如何使用 Firebase 托管来托管图像?

为啥我从托管在 Firebase 上的 NextJs 应用程序仅针对 POST 请求收到“502 网关”错误?

将 .well-known/assetlinks.json 上传到 Mac 上的 Firebase 托管