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

过去,我已经成功地将AngularJS应用程序部署到了S3,并启用了html5mode ,以允许无散列URL。

但是,对于我目前的项目,我需要把站点的Angular部分放到一个子目录( /app )中,并且有很大的麻烦。

我已经尝试了一些东西,最明显的是下面的东西,但是它导致了redirect循环,我不相信有反正规则匹配来避免这样的问题:

 <RoutingRules> <RoutingRule> <Condition> <KeyPrefixEquals>app/</KeyPrefixEquals> </Condition> <Redirect> <ReplaceKeyPrefixWith>app/#</ReplaceKeyPrefixWith> </Redirect> </RoutingRule> </RoutingRules> 

我也尝试过把404引导到app /(也是/app/# /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/#

你真的很接近,但是S3路由规则还有一些细节需要考虑:

HttpErrorCodeReturnedEquals元素是否定匹配的一种forms,但是不存在的对象可能导致404,也可能导致403。这取决于存储桶策略。 您需要确定哪种情况适合您,或者只需处理路由规则中的两个条件。

另外,路由规则不是通过最佳匹配来处理的 – 它们似乎是通过第一次匹配来处理的…所以您实际上想要首先使用最长的前缀来构build您的路由规则。

以下是testing和为我工作。 如果它不起作用,请确保您的浏览器caching清除(因为S3路由规则redirect是301s,浏览器喜欢caching它们),并validation您没有其他redirect,但前缀较短,从而错误地捕获请求。

我假设你已经在/app/index.html有一个文档,并且控制台中的“Index Document”列出了“index.html”作为索引文档。 这使得/ app /的请求将返回/app/index.html, 浏览器的地址栏仍然会读取“/ app /”。

生成SPA所需的redirect…如果我们看到一个前缀为/ app /的请求,并且该对象不存在,我们希望通过replace/ app / with / app /#/来redirect请求。 只有当没有这样的文件。 “没有这样的文件”testing是至关重要的,因为否则这个规则将导致请求“/ app /”被redirect,在一个无限循环,404testing可能不是正确的testing,如上所述。 由于请求者没有权限知道对象是否存在,所以我的存储区在丢失的对象上返回403。 您需要为您的configurationfind正确的值。

使用以下规则,/ app / anyfoo被redirect到/ app /#/ anyfoo,但/ app /不会,因为/ app /实际上匹配索引文档。

 <RoutingRule> <Condition> <KeyPrefixEquals>app/</KeyPrefixEquals> <HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals> </Condition> <Redirect> <ReplaceKeyPrefixWith>app/#/</ReplaceKeyPrefixWith> </Redirect> </RoutingRule> 

最后,我们需要将“app”redirect到“app /”,这样S3才会明白索引文件是需要的。

您的存储桶可能已经在做这个部分,如果是这样,那么上面不应该打破它,因为redirect只发生在键不匹配一个对象时,并且/ app /不会触发该规则,因为它隐式地返回索引文件。

但是,在我testing过的存储桶中,有一个最终规则将所有不存在对象的请求redirect到完全不同主机名的相同path。

这造成了/ app,而没有结尾的斜杠,对我来说,跟随通配符redirecgt到不同的网站,这是错误的。 如果你有这样一个规则,你需要/ app来正确地返回/app/index.html页面,那么遵循上述规则的下面的规则就可以完成这个目的,就像S3一样处理它,如果我没有制定适用的规则,

这个最终规则应该只匹配“/ app”…它也会匹配“/ app /”本身的请求,但是由于“/ app /”不会生成403,所以它不匹配那里没有问题。 它也会匹配“/ app / anyfoo”,但这些请求将永远不会到达这里,因为它们已经被先前的规则捕获和redirect。

 <RoutingRule> <Condition> <KeyPrefixEquals>app</KeyPrefixEquals> <HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals> </Condition> <Redirect> <ReplaceKeyPrefixWith>app/</ReplaceKeyPrefixWith> </Redirect> </RoutingRule> 

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