我之前曾成功将 AngularJS 应用程序部署到 S3,并html5mode
启用了无哈希 URL。
然而,对于我当前的项目,我需要将站点的 Angular 部分放入子目录(/app
),并且遇到了很大的麻烦。
我尝试了一些方法,最值得注意的是以下方法,但它导致了重定向循环,并且我认为没有办法采用负面规则匹配来避免这样的问题:
<RoutingRules>
<RoutingRule>
<Condition>
<KeyPrefixEquals>app/</KeyPrefixEquals>
</Condition>
<Redirect>
<ReplaceKeyPrefixWith>app/#</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
</RoutingRules>
我也尝试过通过将 404 定向到 app/(还有/app/#
、/app/index.html
、/app/index.html#
)来处理它们,但没有任何效果使我的应用程序按照我想要的方式工作。以下示例会导致我的 angular 应用程序中出现意外错误:
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<HostName>mytest.s3-website-us-east-1.amazonaws.com</HostName>
<ReplaceKeyWith>app/index.html</ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
我可以使用什么规则来将所有以 开头的请求定向/app
到/app/#
?
答案1
您确实很接近了,但是您需要考虑 S3 路由规则的一些细微差别:
元素HttpErrorCodeReturnedEquals
是反向匹配的一种形式,但不存在的对象可能会导致 404,也可能导致 403。这取决于存储桶策略。您需要确定哪种情况适合您,或者只需在路由规则中处理这两种情况即可。
此外,路由规则不是按最佳匹配处理的——它们似乎是按第一个匹配处理的……所以您实际上希望首先使用最长的前缀来构建路由规则。
以下内容已测试过,对我有效。如果它对您不起作用,请确保您的浏览器缓存已清除(因为 S3 路由规则重定向是 301,浏览器喜欢缓存它们),并验证您没有其他前缀较短的重定向会错误地捕获请求。
我假设您已在 /app/index.html 处有一个文档,并且控制台中的“索引文档”将“index.html”列为索引文档。这样,对 /app/ 的请求将返回 /app/index.html但浏览器的地址栏仍会显示“/app/”。
生成 SPA 所需的重定向...如果我们看到带有 /app/ 前缀的请求并且该对象不存在,我们希望通过将 /app/ 替换为 /app/#/ 来重定向请求,但是除非没有这样的文件。“没有这样的文件”测试至关重要,因为否则此规则将导致对“/app/”的请求被重定向,陷入无限循环,并且 404 测试可能不是正确的测试,如上所述。我的存储桶在缺少对象时返回 403,因为请求者无权知道该对象是否存在。您需要为您的配置找到正确的值。
根据以下规则,/app/anyfoo 将被重定向到 /app/#/anyfoo,但 /app/ 不会,因为 /app/ 实际上与索引文档匹配。
<RoutingRule>
<Condition>
<KeyPrefixEquals>app/</KeyPrefixEquals>
<HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<ReplaceKeyPrefixWith>app/#/</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
最后,我们需要将“app”的请求重定向到“app/”,以便 S3 明白需要索引文档。
您的存储桶可能已经在执行此部分,如果是,则上述操作不应破坏它,因为重定向仅在密钥与对象不匹配时发生,并且 /app/ 不会触发该规则,因为它隐式返回索引文档。
然而...在我测试的存储桶中,有一条最终规则可以重定向全部请求,其中对象不存在,到完全不同的主机名的相同路径。
对我来说,这导致 /app(没有尾部斜杠)按照该通配符重定向到其他网站,这是错误的。如果您有这样的规则,并且需要让 /app 正确返回 /app/index.html 页面,那么以下规则,放在上述规则之后,如果我没有制定全面规则,就可以以与 S3 处理该目的相同的方式实现该目的。
这条最终规则应该只匹配“/app”...它也会匹配对“/app/”本身的请求,但由于“/app/”不会生成 403,因此它不匹配,因此这里没有问题。它还会匹配“/app/anyfoo”,但这些请求永远不会到达这里,因为它们已被前一条规则捕获和重定向。
<RoutingRule>
<Condition>
<KeyPrefixEquals>app</KeyPrefixEquals>
<HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<ReplaceKeyPrefixWith>app/</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
当然,最后这条规则的滑稽副作用是,一个无意义的请求(例如“/applesauce”)会重定向到“/app/lesauce”,然后重定向到“/app/#/lesauce”,但这是无害的,因为重定向依赖于实际不存在的引用对象。如果 /applesauce 是合法路径,则不会触发重定向。您可以通过在对象元数据中的关键级别重定向“app”而不是路由规则来解决这个问题,但我将把这留给读者作为练习,因为这最后一步可能不是必需的,具体取决于存储桶配置。