AngularJS HTML5 Mode – Como links diretos funcionam sem mudanças específicas do servidor?

Nota: Esta questão também pode ler:

Como suportar bookmarking de frameworks mvc do lado do cliente sem hashbang em Java.

Estou fazendo a transição de um aplicativo angular que usa hashtags para um que é html5mode . Eu defini com sucesso

 $locationProvider.html5Mode(true); 

E todos os links da página de destino (index.html) funcionam bem.

O problema é que, se URLs parciais são referenciados diretamente, recebo um 404, naturalmente, uma vez que as definições de terminal do servidor não são acopladas a rotas definidas pelo lado do cliente.

Assim, sem o HTML5, temos hashbang não-amigáveis ​​para o SEO, mas com ele não podemos marcar nada além da página de destino (a página que inicializa angular).

Por que funciona se você solicitar a página de destino padrão (index.html) primeiro, ou seja, htpp: //mydomain.com/:

  1. Navegador solicita index.html do servidor
  2. Servidor retorna index.html e o navegador carrega a estrutura angular
  3. As alterações de URL são enviadas para o roteador do lado do cliente e as partes / partições apropriadas são carregadas.

Por que não funciona se (por exemplo) http://mydomain.com/foo for solicitado diretamente no navegador:

  1. O navegador solicita mydomain / foo do servidor.
  2. Recurso não existe
  3. Servidor devolve 404

Algo está faltando nessa história, eu simplesmente não sei o quê. Aqui estão as duas únicas respostas que posso ver …

  • É por design. É assim que deveria funcionar? Os usuários devem sempre acessar a página de bootstrap do framework MVC do cliente (geralmente index.html) e navegar a partir daí. Isso não é ideal porque o estado não pode ser salvo e não há como marcar … para não mencionar o rastreamento.
  • Solução de servidor. Isso funcionou com um truque do lado do servidor? Por exemplo, em todas as solicitações, retorne index.html e chame imediatamente o roteador com o contexto adicional. Se assim for, isso é contra o objective que o AngularJS é completamente do lado do cliente e parece um hack.

A documentação do AngularJS na verdade menciona isso

Lado do servidor Usar este modo requer reescrita de URL no lado do servidor, basicamente você tem que rewrite todos os seus links para o ponto de input do seu aplicativo (por exemplo, index.html)

Nesse caso, uma solução baseada em Java é informar ao servidor “mapear todos os URLs para index.html”. Isso pode ser feito em qualquer servidor HTTP ou contêiner. Implementei isso usando Java / Servet, pois quero que meu aplicativo seja independente de servidor HTTP (ou seja, Apache versus NginX ou Tomcat / JBoss apenas).

No web.xml:

   index.jsp   StaticServlet /index.jsp   StaticServlet /app  

E index.jsp simplesmente se parece com:

 <%@ include file="index.html" %> 

E adicione o seguinte à tag no index.html:

  

Passei algum tempo pensando sobre isso para o meu site PHP. Eu penduro todo o código do meu servidor fora da rota / api para mantê-lo separado do Angular. Aqui está a solução que eu criei atualizando a configuração do meu apache:

 RewriteEngine on #let the php framework do its thing RewriteRule ^(api/.*)$ index.php?url=$1 [QSA,L,NC] #let angular do its thing RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*) index.html [NC,L] 

Eu escrevi como eu fui sobre isso usando o framework Flight PHP em http://www.awnage.com/2013/10/10/taking-flight-with-angularjs/

Os URLs aos quais você vincula e coloca na barra de endereços do usuário devem se referir ao conteúdo válido no servidor e, se possível, devem consultar o conteúdo correto . Claro, você pode apenas servir a mesma página para cada URL, e ter o código do cliente desligado e carregar o conteúdo real, e as coisas funcionam da mesma maneira que no mundo do hash-URL. Na verdade, esse é o caminho menos código a seguir. Mas também se qualifica como “quebrar a internet”, e é por isso que a HTML5 e a History API oferecem uma maneira de vincular a URLs semanticamente corretas .

Como um pequeno exemplo, se você acessar https://github.com/kriskowal/q e clicar em “exemplos”, o código do lado do cliente carregará o diretório “examples” no navegador de arquivos sem sair da página, e a barra de URL lerá https://github.com/kriskowal/q/tree/master/examples . Se você acessar https://github.com/kriskowal/q/tree/master/examples diretamente, obterá o conteúdo do diretório “examples” enviado diretamente para o seu navegador, sem intermediar o código do lado do cliente. Sim, isso é mais difícil de ser feito e talvez impossível em um “aplicativo de página única”, mas é a coisa certa a se fazer sempre que possível.