如何使用重写规则将 SPA 放置在 S3 状态网站子目录中?

Mar*_*ine 1 rewrite amazon-s3

过去,我已成功将 AngularJS 应用程序部署到 S3 并html5mode启用,以允许无哈希 URL。

但是,对于我当前的项目,我需要将站点的 Angular 部分放入子目录 ( /app) 中,但遇到了重大问题。

我已经尝试了一些事情,最值得注意的是以下内容,但它会导致重定向循环,而且我认为无论如何都无法使用否定规则匹配来避免这样的问题:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>app/</KeyPrefixEquals>
        </Condition>
        <Redirect>
            <ReplaceKeyPrefixWith>app/#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>
Run Code Online (Sandbox Code Playgroud)

我还尝试通过将 404 引导到 app/(还有/app/#, /app/index.html, /app/index.html#)来处理 404 ,但没有任何效果可以使我的应用程序按照我想要的方式工作。在我的 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>
Run Code Online (Sandbox Code Playgroud)

我可以使用什么规则来让所有以/app定向到开头的请求/app/#

Mic*_*bot 5

您真的很接近,但是您需要考虑 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>
Run Code Online (Sandbox Code Playgroud)

最后,我们需要将“app”请求重定向到“app/”,以便 S3 理解需要索引文档。

您的存储桶可能已经在执行此部分,如果是,则上述内容不应破坏它,因为重定向仅在键与对象不匹配时发生,并且 /app/ 不会触发该规则,因为它隐式返回索引文档。

但是......在我测试这个的存储桶中,有一个最终规则将对象不存在的所有请求重定向到完全不同的主机名的相同路径。

这导致 /app 没有尾部斜杠,对我来说,遵循通配符 redirecgt 到不同的站点,这是错误的。如果您有这样的规则并且您需要获取 /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>
Run Code Online (Sandbox Code Playgroud)

当然,最后一条规则的滑稽副作用是一个无意义的请求,例如“/applesauce”重定向到“/app/lesauce”然后重定向到“/app/#/lesauce”,但这是相当无害的,因为重定向取决于实际不存在的引用对象。如果 /applesauce 是合法路径,则不会触发重定向。您可以通过在对象元数据的关键级别重定向“应用程序”而不是路由规则来解决此问题,但我会将其作为练习留给读者,因为这最后一步可能不是必需的,具体取决于存储桶配置。