Roteiro de hospedagem de site estático S3 Todos os caminhos para Index.html

250

Estou usando o S3 para hospedar um aplicativo javascript que usará pushStates HTML5. O problema é que, se o usuário marcar um dos URLs como favorito, ele não resolverá nada. O que eu preciso é a capacidade de receber todas as solicitações de URL e exibir o index.html raiz no meu bucket S3, em vez de apenas fazer um redirecionamento completo. Em seguida, meu aplicativo javascript poderia analisar o URL e exibir a página apropriada.

Existe alguma maneira de dizer ao S3 para servir o index.html para todas as solicitações de URL em vez de fazer redirecionamentos? Isso seria semelhante à configuração do apache para lidar com todas as solicitações recebidas, exibindo um único index.html, como neste exemplo: https://stackoverflow.com/a/10647521/1762614 . Eu realmente gostaria de evitar a execução de um servidor web apenas para lidar com essas rotas. Fazer tudo do S3 é muito atraente.

Mark Nutter
fonte
Você encontrou uma solução para isso?
W2lame 12/08/14

Respostas:

302

É muito fácil resolvê-lo sem invasões de URL, com a ajuda do CloudFront.

  • Crie um depósito S3, por exemplo: reagir
  • Crie distribuições do CloudFront com estas configurações:
    • Objeto raiz padrão : index.html
    • Nome de domínio de origem : domínio de bloco S3, por exemplo: react.s3.amazonaws.com
  • Vá para a guia Páginas de erro , clique em Criar resposta de erro personalizada :
    • Código de erro HTTP : 403: Proibido (404: não encontrado, no caso do site estático S3)
    • Personalizar resposta do erro : Sim
    • Caminho da página de resposta : /index.html
    • Código de resposta HTTP : 200: OK
    • Clique em Criar
lenaten
fonte
8
Obrigado. A melhor resposta até agora.
JGB
e o que não é tão óbvio, você mantém a localização para poder fazer o roteamento "natural".
Lukasz Marek Sielski
5
isso funcionou como um encanto para mim, apenas o código de erro personalizado de que eu precisava era 404, não 403
Jeremy S.
4
Um pouco de hack, mas funciona muito bem :) Seria bom se o CloudFront nos permitisse mapear uma série de caminhos para um arquivo S3 (sem redirecionamento).
22416 Bob
3
Isso não está funcionando para mim. Esta solução sempre redireciona para a página inicial e não as páginas corretas ...
Jim
201

A maneira como consegui fazer isso funcionar é a seguinte:

Na seção Editar regras de redirecionamento do S3 Console para seu domínio, adicione as seguintes regras:

<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>yourdomainname.com</HostName>
      <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

Isso redirecionará todos os caminhos que resultam em um 404 não encontrado no domínio raiz com uma versão hash-bang do caminho. Portanto, http://seudominio.com.br/posts será redirecionado para http://seudominio.com.br/#!/posts, desde que não haja arquivo em / posts.

Para usar HTML5 pushStates, no entanto, precisamos atender a essa solicitação e estabelecer manualmente o pushState adequado com base no caminho hash-bang. Então adicione isso na parte superior do seu arquivo index.html:

<script>
  history.pushState({}, "entry page", location.hash.substring(1));
</script>

Isso pega o hash e o transforma em um pushState HTML5. A partir deste ponto, você pode usar os pushStates para ter caminhos não hash-bang no seu aplicativo.

Mark Nutter
fonte
4
Esta solução funciona muito bem! De fato, o angularjs fará automaticamente o histórico pushState se o modo html estiver configurado.
Wcandillon #
1
Isso falhará com a versão mais antiga do IE se você tiver parâmetros GET incluídos em seus URLs, correto? Como você contorna essa questão?
precisa saber é o seguinte
3
Obrigado! Isso funcionou bem para mim na espinha dorsal com um pequeno ajuste. Eu adicionei em uma verificação para navegadores mais antigos: <script language="javascript"> if (typeof(window.history.pushState) == 'function') { window.history.pushState(null, "Site Name", window.location.hash.substring(2)); } else { window.location.hash = window.location.hash.substring(2); } </script>
AE Gray
10
Sucedeu com react-routercom que a solução usando HTML 5 pushStates e<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
Felix D.
5
Ele não funciona no safari e é um grande problema com a estratégia de implantação. Escrever um js pequeno para redirecionar é um tipo de abordagem surrada. Além disso, o número de redirecionamentos também é um problema. Estou tentando descobrir se existe uma maneira de todos os URLs do S3 apontarem para index.html sempre.
moha297
129

Existem alguns problemas com a abordagem baseada em S3 / Redirect mencionada por outros.

  1. Os redirecionamentos múltiplos acontecem quando os caminhos do seu aplicativo são resolvidos. Por exemplo: www.myapp.com/path/for/test é redirecionado como www.myapp.com/#/path/for/test
  2. Há uma cintilação na barra de URL quando o '#' vai e vem devido à ação da estrutura do seu SPA.
  3. O SEO é impactado porque - 'Ei! O Google força a mão a redirecionar '
  4. O suporte do Safari para o seu aplicativo é um desafio.

A solução é:

  1. Verifique se você tem a rota de índice configurada para o seu site. Principalmente é index.html
  2. Remover regras de roteamento das configurações do S3
  3. Coloque um Cloudfront na frente do seu bucket S3.
  4. Configure regras da página de erro para sua instância do Cloudfront. Nas regras de erro, especifique:

    • Código de erro HTTP: 404 (e 403 ou outros erros conforme a necessidade)
    • Erro em cache TTL mínimo (segundos): 0
    • Personalizar resposta: Sim
    • Caminho da página de resposta: /index.html
    • Código de resposta HTTP: 200

      1. Para necessidades de SEO +, verifique se o index.html não faz cache, faça o seguinte:
    • Configure uma instância do EC2 e configure um servidor nginx.

    • Atribua um IP público à sua instância do EC2.
    • Crie um ELB que tenha a instância do EC2 que você criou como uma instância
    • Você deve poder atribuir o ELB ao seu DNS.
    • Agora, configure seu servidor nginx para fazer o seguinte: Proxy_passar todas as solicitações para sua CDN (apenas para index.html, servir outros ativos diretamente da sua nuvem) e para bots de pesquisa, redirecione o tráfego conforme estipulado por serviços como Prerender.io

Posso ajudar em mais detalhes com relação à configuração do nginx, basta deixar uma nota. Aprendi da maneira mais difícil.

Depois que a distribuição da frente da nuvem for atualizada. Invalide seu cache do cloudfront uma vez para estar no modo intocado. Bata o URL no navegador e tudo deve ser bom.

moha297
fonte
6
desde S3 responde com um 403 Proibido quando um arquivo não existe, eu acho que o passo 4 acima tem de ser duplicada para HTTP código de erro 403, bem
Andreas
4
Para mim esta é a única resposta que resulta em um esperado (aceite) comportamento
mabe.berlin
1
@ moha297 no ponto 5, você está basicamente configurando seu site para buscar no nginx que, em seguida, procura proxies da CDN (exceto para index.html e solicitações de rastreador)? Se for esse o caso, você não perderia o benefício dos servidores de borda da CDN?
Rahul Patel
2
@ moha297 você pode explicar esse comentário: "Você nunca deve veicular index.html de uma CDN"? Não vejo o problema de exibir index.html do S3 com o CloudFront.
31817 Carl G
1
Consulte stackoverflow.com/a/10622078/4185989 para obter mais informações sobre como um TTL de 0 é tratado (versão curta: ele é armazenado em cache pelo Cloudfront, mas umIf-Modified-Since solicitação GET é enviada para a origem) - pode ser uma consideração útil para pessoas que não desejam configurar um servidor como na etapa 5.
jmq
18

É tangencial, mas aqui está uma dica para quem usa a biblioteca React Router da Rackt com histórico de navegador (HTML5) que deseja hospedar no S3.

Suponha que um usuário visite /foo/bearseu site estático hospedado no S3. Dada a sugestão anterior de David , as regras de redirecionamento as enviarão para /#/foo/bear. Se o seu aplicativo foi criado usando o histórico do navegador, isso não será muito bom. No entanto, seu aplicativo está carregado neste momento e agora pode manipular o histórico.

Incluindo o histórico Rackt em nosso projeto (consulte também Utilizando históricos personalizados no projeto React Router), você pode adicionar um ouvinte que esteja ciente dos caminhos do histórico de hash e substituí-lo conforme apropriado, conforme ilustrado neste exemplo:

import ReactDOM from 'react-dom';

/* Application-specific details. */
const route = {};

import { Router, useRouterHistory } from 'react-router';
import { createHistory } from 'history';

const history = useRouterHistory(createHistory)();

history.listen(function (location) {
  const path = (/#(\/.*)$/.exec(location.hash) || [])[1];
  if (path) history.replace(path);
});

ReactDOM.render(
  <Router history={history} routes={route}/>,
  document.body.appendChild(document.createElement('div'))
);

Para recapitular:

  1. A regra de redirecionamento S3 de David direcionará /foo/bearpara/#/foo/bear .
  2. Seu aplicativo será carregado.
  3. O ouvinte do #/foo/bearhistórico detectará a notação do histórico.
  4. E substitua o histórico pelo caminho correto.

Link Tag funcionarão conforme o esperado, assim como todas as outras funções do histórico do navegador. A única desvantagem que notei é o redirecionamento intersticial que ocorre na solicitação inicial.

Isso foi inspirado por uma solução para o AngularJS e suspeito que possa ser facilmente adaptado a qualquer aplicativo.

Michael Ahlers
fonte
2
Isso me ajudou Michael, obrigado! Você pode alterar sua referência do histórico e usar o BrowserHistory. iebrowserHistory.listen
Marshall Moutenot
De nada! Feliz em ajudar. Além disso, concordei e, para esse caso de uso específico, atualizei o snippet para resolver um aviso de descontinuação do React Router.
Michael Ahlers
Com liberação de reagir-router v3.0.0 Isso não funciona, v3.0.0 porque reagem-router utiliza História v3.0.0
Varand Pezeshkian
Alguma idéia de como evitar history.listen loop de chamada infinita? Causado pela substituição do caminho, eu acho.
Mirko Flyktman
14

Eu vejo 4 soluções para este problema. Os três primeiros já foram abordados em respostas e o último é minha contribuição.

  1. Defina o documento de erro como index.html.
    Problema : o corpo da resposta estará correto, mas o código de status será 404, o que prejudica o SEO.

  2. Defina as regras de redirecionamento.
    Problema : o URL poluído #!e a página pisca quando carregada.

  3. Configure o CloudFront.
    Problema : todas as páginas retornarão 404 da origem, portanto, você deve escolher se não armazenará nada em cache (TTL 0, conforme sugerido) ou se armazenará em cache e terá problemas ao atualizar o site.

  4. Pré-renderize todas as páginas.
    Problema : trabalho adicional para pré-renderizar páginas, especialmente quando as páginas são alteradas com frequência. Por exemplo, um site de notícias.

Minha sugestão é usar a opção 4. Se você pré-renderizar todas as páginas, não haverá erros 404 para as páginas esperadas. A página carregará bem e a estrutura assumirá o controle e agirá normalmente como um SPA. Você também pode definir o documento de erro para exibir uma página error.html genérica e uma regra de redirecionamento para redirecionar os erros 404 para uma página 404.html (sem o hashbang).

Em relação aos 403 erros proibidos, não os deixo acontecer. No meu aplicativo, considero que todos os arquivos no bucket do host são públicos e defino isso com a opção Todos com a permissão de leitura . Se o seu site tiver páginas privadas, permitir que o usuário veja o layout HTML não deve ser um problema. O que você precisa proteger são os dados e isso é feito no back-end.

Além disso, se você tiver ativos privados, como fotos de usuário, poderá salvá-los em outro depósito. Como os ativos privados precisam do mesmo cuidado que os dados e não podem ser comparados aos arquivos de ativos usados ​​para hospedar o aplicativo.

Zanon
fonte
1
e seu site tem um ótimo exemplo de uso para pré-renderização para todas as páginas. zanon.io/posts/… .- Obrigado
frekele
Essa quarta abordagem aborda o usuário que recarrega a URL pushState? Ele lida com a navegação muito bem, mas, ao recarregar, ainda chegará ao servidor.
Alpha
@ Alpha, não tenho certeza se entendi sua pergunta corretamente, mas em uma atualização, ela funcionaria como uma nova solicitação. O S3 receberia a solicitação e retornaria a página pré-renderizada novamente. Não há servidor neste caso.
Zanon
@Zanon Ah, acho que entendo. Eu pensei que era para armazenar em cache as páginas pré-renderizadas e evitar os recursos inexistentes do S3. Isso deixaria de fora as rotas que possuem elementos dinâmicos, certo?
Alpha
1
@Zanon eu finalmente entendo - obrigado! Sim, foi o que eu quis dizer. :)
Alfa
13

Encontrei o mesmo problema hoje, mas a solução do @ Mark-Nutter estava incompleta para remover o hashbang do meu aplicativo angularjs.

Na verdade, você precisa ir para Editar permissões , clicar em Adicionar mais permissões e adicionar a lista correta no seu balde a todos. Com essa configuração, o AWS S3 agora poderá retornar o erro 404 e, em seguida, a regra de redirecionamento detectará o caso corretamente.

Bem assim : insira a descrição da imagem aqui

E então você pode ir para Editar Regras de Redirecionamento e adicionar esta regra:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <HostName>subdomain.domain.fr</HostName>
            <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

Aqui você pode substituir o nome do host subdomínio.domínio.fr pelo seu domínio e o KeyPrefix #! / Se você não usar o método hashbang para fins de SEO.

Obviamente, tudo isso funcionará apenas se você já tiver configurado o html5mode no seu aplicativo angular.

$locationProvider.html5Mode(true).hashPrefix('!');
davidbonachera
fonte
meu único problema com isso é que você tem um flash de hashbang, que não possui algo como uma regra nginx. O usuário está em uma página e atualiza: / products / 1 -> #! /
Products
1
Eu acho que você deve adicionar uma regra para um erro 403 em vez de conceder permissões de lista a todos.
precisa saber é o seguinte
11

A solução mais fácil para fazer com que o aplicativo Angular 2+ veiculado no Amazon S3 e URLs diretos funcionem é especificar index.html como documentos de Índice e Erro na configuração do bucket do S3.

insira a descrição da imagem aqui

Sergey Kandaurov
fonte
11
Esta é a mesma resposta desta resposta com baixa votação . Funciona bem, mas apenas para bodya resposta. O código de status será 404 e prejudicará o SEO.
Zanon 14/05
Como isso funciona apenas para os bodyscripts que você importar, headeles não funcionarão quando você atingir diretamente qualquer uma das sub-rotas no seu site
Mohamed Hajr
4

como o problema ainda está lá, eu acho que joguei outra solução. Meu caso foi que eu desejava implantar automaticamente todas as solicitações pull no s3 para teste antes de mesclar, tornando-as acessíveis em [mydomain] / pull-orders / [pr number] /
(por exemplo, www.example.com/pull-requests/822/ )

Que eu saiba, os cenários que não pertencem às regras s3 permitiriam ter vários projetos em um bucket usando o roteamento html5; portanto, embora a sugestão mais votada funcione para um projeto na pasta raiz, não para vários projetos em suas próprias subpastas.

Então apontei meu domínio para o meu servidor, onde a seguinte configuração do nginx fez o trabalho

location /pull-requests/ {
    try_files $uri @get_files;
}
location @get_files {
    rewrite ^\/pull-requests\/(.*) /$1 break;
    proxy_pass http://<your-amazon-bucket-url>;
    proxy_intercept_errors on;
    recursive_error_pages on;
    error_page 404 = @get_routes;
}

location @get_routes {
    rewrite ^\/(\w+)\/(.+) /$1/ break;
    proxy_pass http://<your-amazon-bucket-url>;
    proxy_intercept_errors on;
    recursive_error_pages on;
    error_page 404 = @not_found;
}

location @not_found {
    return 404;
}

ele tenta obter o arquivo e, se não for encontrado, assume que é a rota html5 e tenta isso. Se você possui uma página angular 404 para rotas não encontradas, nunca acessará @not_found e retornará a página 404 angular em vez de arquivos não encontrados, que podem ser corrigidos com alguma regra if em @get_routes ou algo assim.

Eu tenho que dizer que não me sinto muito à vontade na área de configuração do nginx e usando o regex, eu trabalhei com algumas tentativas e erros, portanto, enquanto isso funciona, tenho certeza de que há espaço para melhorias e, por favor, compartilhe seus pensamentos .

Nota : remova as regras de redirecionamento s3 se você as tiver na configuração do S3.

e btw funciona no Safari

Andrew Arnautov
fonte
oi .. obrigado pela solução ... onde você coloca esse arquivo conf nginx para implantação s3. é o mesmo que o beanstalk elástico, onde eu preciso criar a pasta .exextensions e colocá-lo no arquivo proxy.config?
precisa saber é o seguinte
@ user3124360 Não tenho certeza sobre o beanstack elástico, mas no meu caso aponto meu nome de domínio para a instância ec2 e tenho a configuração nginx lá. Então, o pedido vai CLIENT -> DNS -> EC2 -> S3 -> CLIENT.
Andrew Arnautov 23/01
sim, estou fazendo algo muito semelhante ... com a configuração do nginx aqui github.com/davezuko/react-redux-starter-kit/issues/1099 ... obrigado por postar seu arquivo conf .. vejo como desenvolver esse EC2 -> Conexão S3 agora
user3124360
3

Estava procurando o mesmo tipo de problema. Acabei usando uma mistura das soluções sugeridas descritas acima.

Primeiro, eu tenho um bucket s3 com várias pastas, cada pasta representa um site react / redux. Eu também uso o cloudfront para invalidação de cache.

Então, eu tive que usar as regras de roteamento para dar suporte ao 404 e redirecioná-las para uma configuração de hash:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website1/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website1#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website2/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website2#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website3/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website3#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

No meu código js, ​​eu precisava lidar com isso com uma baseNameconfiguração para o react-router. Antes de tudo, verifique se suas dependências são interoperáveis, eu instalei com as history==4.0.0quais era incompatível react-router==3.0.1.

Minhas dependências são:

  • "history": "3.2.0",
  • "reagir": "15.4.1",
  • "react-redux": "4.4.6",
  • "react-router": "3.0.1",
  • "react-router-redux": "4.0.7",

Criei um history.jsarquivo para carregar o histórico:

import {useRouterHistory} from 'react-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';

export const browserHistory = useRouterHistory(createBrowserHistory)({
    basename: '/website1/',
});

browserHistory.listen((location) => {
    const path = (/#(.*)$/.exec(location.hash) || [])[1];
    if (path) {
        browserHistory.replace(path);
    }
});

export default browserHistory;

Esse trecho de código permite manipular o 404 enviado pelo servidor com um hash e substituí-lo no histórico para carregar nossas rotas.

Agora você pode usar esse arquivo para configurar sua loja e seu arquivo raiz.

import {routerMiddleware} from 'react-router-redux';
import {applyMiddleware, compose} from 'redux';

import rootSaga from '../sagas';
import rootReducer from '../reducers';

import {createInjectSagasStore, sagaMiddleware} from './redux-sagas-injector';

import {browserHistory} from '../history';

export default function configureStore(initialState) {
    const enhancers = [
        applyMiddleware(
            sagaMiddleware,
            routerMiddleware(browserHistory),
        )];

    return createInjectSagasStore(rootReducer, rootSaga, initialState, compose(...enhancers));
}
import React, {PropTypes} from 'react';
import {Provider} from 'react-redux';
import {Router} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import variables from '!!sass-variable-loader!../../../css/variables/variables.prod.scss';
import routesFactory from '../routes';
import {browserHistory} from '../history';

const muiTheme = getMuiTheme({
    palette: {
        primary1Color: variables.baseColor,
    },
});

const Root = ({store}) => {
    const history = syncHistoryWithStore(browserHistory, store);
    const routes = routesFactory(store);

    return (
        <Provider {...{store}}>
            <MuiThemeProvider muiTheme={muiTheme}>
                <Router {...{history, routes}} />
            </MuiThemeProvider>
        </Provider>
    );
};

Root.propTypes = {
    store: PropTypes.shape({}).isRequired,
};

export default Root;

Espero que ajude. Você notará que, com essa configuração, eu uso o injetor redux e um injetor homebrew sagas para carregar o javascript de forma assíncrona, via roteamento. Não se importe com essas linhas.

Guillaume Cisco
fonte
3

Agora você pode fazer isso com o Lambda @ Edge para reescrever os caminhos

Aqui está uma função lambda @ Edge em funcionamento:

  1. Crie uma nova função Lambda, mas use um dos Blueprints pré-existentes em vez de uma função em branco.
  2. Procure por "nuvem" e selecione geração de resposta à nuvem nos resultados da pesquisa.
  3. Após criar a função, substitua o conteúdo pelo abaixo. Também tive que alterar o tempo de execução do nó para 10.x porque o cloudfront não suportava o nó 12 no momento da escrita.
'use strict';
exports.handler = (event, context, callback) => {

    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');

    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    return callback(null, request);
};

Nos seus comportamentos na nuvem, você os editará para adicionar uma chamada à função lambda em "Solicitação do visualizador" insira a descrição da imagem aqui

Tutorial completo: https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/

Loren
fonte
1
Seu exemplo de código perde apenas uma linha:return callback(null, request);
Pherrymason
2

Se você chegou aqui procurando uma solução que funcione com o React Router e o AWS Amplify Console - você já sabe que não pode usar as regras de redirecionamento do CloudFront diretamente, pois o Amplify Console não expõe o CloudFront Distribution para o aplicativo.

A solução, no entanto, é muito simples - você só precisa adicionar uma regra de redirecionamento / reescrita no Amplify Console como esta:

Regra de reconfiguração do console Amplify para o roteador React

Consulte os links a seguir para obter mais informações (e regra de cópia amigável na captura de tela):

Yaro
fonte
0

Eu mesmo estava procurando uma resposta para isso. O S3 parece suportar apenas redirecionamentos, você não pode simplesmente reescrever o URL e retornar silenciosamente um recurso diferente. Estou pensando em usar meu script de construção para simplesmente fazer cópias do meu index.html em todos os locais de caminho necessários. Talvez isso funcione para você também.

Ed Thomas
fonte
2
A geração de arquivos de índice para cada caminho também me passou pela cabeça, mas seria difícil ter caminhos dinâmicos como exemplo.com/groups/5/show . Se você vir minha resposta a essa pergunta, acredito que resolve o problema em sua maior parte. É um pouco complicado, mas pelo menos funciona.
Mark Nutter
Melhor implantar atrás de um servidor nginx e retornar index.html para todos os URLs recebidos. Fiz isso com sucesso com a implantação heroku de aplicativos de brasa.
moha297
-3

Apenas para colocar a resposta extremamente simples. Basta usar a estratégia de localização de hash para o roteador se você estiver hospedando no S3.

exportar constante AppRoutingModule: ModuleWithProviders = RouterModule.forRoot (rotas, {useHash: true, scrollPositionRestoration: 'enabled'});

Meester Over
fonte