Você estava muito perto, mas há algumas sutilezas com as regras de roteamento do S3 que você precisa levar em consideração:
O elemento HttpErrorCodeReturnedEquals
é uma forma de correspondência negativa, mas enquanto um objeto que não está presente pode causar um 404, ele também pode causar um 403. Isso depende da política de buckets. Você precisará determinar qual é o seu caso ou apenas manipular ambas as condições nas regras de roteamento.
Além disso, as regras de roteamento não são processadas pela melhor correspondência - elas parecem ser processadas pela primeira correspondência ... então você realmente deseja criar suas regras de roteamento com os maiores prefixos primeiro.
O seguinte é testado e funciona para mim. Se isso não funcionar, verifique se o cache do navegador está limpo (desde que a regra de roteamento do S3 redireciona para 301s e os navegadores adoram armazená-los em cache) e verifique se você não possui outros redirecionamentos com prefixos mais curtos que capturam incorretamente as solicitações. / p>
Suponho que você já tenha um documento em /app/index.html e que "Documento de Índice" no console liste "index.html" como o documento de índice. Isso faz com que as solicitações de / app / retornem /app/index.html , mas a barra de endereços do navegador ainda seja lida "/ app /".
Gerando o redirecionamento necessário para o SPA ... se vermos uma solicitação com um prefixo / app / e o objeto não existir, queremos redirecionar a solicitação substituindo / app / with / app / # /, mas somente se não houver tal arquivo. O teste "no such file" é crucial porque senão essa regra resultaria em solicitações para "/ app /" serem redirecionadas, em um loop infinito, e o teste 404 pode não ser o teste correto, como mencionado acima. Meus buckets retornam 403 em objetos ausentes, pois o solicitante não tem permissão para saber se o objeto existe ou não. Você precisará encontrar o valor correto para sua configuração.
Com a seguinte regra em vigor, / app / anyfoo é redirecionado para / app / # / anyfoo, mas / app / does, porque / app / corresponde realmente ao documento de índice.
<RoutingRule>
<Condition>
<KeyPrefixEquals>app/</KeyPrefixEquals>
<HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<ReplaceKeyPrefixWith>app/#/</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
Finalmente, precisamos que os pedidos de "app" sejam redirecionados para "app /", para que o S3 entenda que o documento de índice é necessário.
Seu bloco já pode estar fazendo essa parte e, se estiver, o acima não deve quebrá-lo, pois o redirecionamento só ocorre quando a chave não corresponde a um objeto e / app / não aciona essa regra. já que implicitamente retorna o documento de índice.
No entanto ... no repositório onde testei isso, há uma regra final que redireciona todas as solicitações, onde o objeto não existe, para o mesmo caminho em um nome de host totalmente diferente.
Isso fez com que o / app, sem a barra final, seguisse esse redirecionamento de caractere curinga para um site diferente, o que estava errado. Se você tiver essa regra e precisar obter / app para retornar corretamente a página /app/index.html, a seguinte regra, colocada após a regra acima , atingirá esse propósito praticamente da mesma forma maneira S3 teria lidado com isso, se eu não tivesse a regra catchall no lugar.
Essa regra final deve corresponder apenas a "/ app" ... ela também corresponderia às solicitações de "/ app /", mas como "/ app /" não gera um 403, ela não corresponde , então não há problema. Também corresponderia a "/ app / anyfoo", mas essas solicitações nunca chegarão aqui, porque elas já foram capturadas e redirecionadas pela regra anterior.
<RoutingRule>
<Condition>
<KeyPrefixEquals>app</KeyPrefixEquals>
<HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<ReplaceKeyPrefixWith>app/</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
Naturalmente, o efeito colateral cômico dessa última regra é que uma solicitação sem sentido, por exemplo, para "/ applesauce" redireciona para "/ app / lesauce" e depois para "/ app / # / lesauce", mas isso é bastante inofensivo, uma vez que os redirecionamentos dependem dos objetos referenciados não existentes. Se / applesauce for um caminho legítimo, o redirecionamento não será disparado. Você pode contornar isso redirecionando "app" no nível de chave nos metadados do objeto em vez de uma regra de roteamento, mas deixarei isso como um exercício para o leitor, já que essa etapa final pode não ser necessária, dependendo da configuração do bucket.