El alojamiento de sitios web estáticos S3 dirige todas las rutas a Index.html

Resuelto Mark Nutter asked hace 54 años • 0 respuestas

Estoy usando S3 para alojar una aplicación javascript que usará HTML5 pushStates. El problema es que si el usuario marca alguna de las URL como favorita, no se resolverá nada. Lo que necesito es la capacidad de aceptar todas las solicitudes de URL y publicar el index.html raíz en mi depósito S3, en lugar de simplemente realizar una redirección completa. Entonces mi aplicación javascript podría analizar la URL y mostrar la página adecuada.

¿Hay alguna forma de indicarle a S3 que proporcione index.html para todas las solicitudes de URL en lugar de realizar redirecciones? Esto sería similar a configurar Apache para manejar todas las solicitudes entrantes entregando un único index.html como en este ejemplo: https://stackoverflow.com/a/10647521/1762614 . Realmente me gustaría evitar ejecutar un servidor web sólo para manejar estas rutas. Hacer todo desde S3 es muy atractivo.

Mark Nutter avatar Jan 01 '70 08:01 Mark Nutter
Aceptado

Es muy fácil solucionarlo sin hacks de URL, con la ayuda de CloudFront.

  • Cree un depósito S3, por ejemplo: reaccionar
  • Cree distribuciones de CloudFront con esta configuración:
    • Objeto raíz predeterminado : index.html
    • Nombre de dominio de origen : dominio del depósito S3, por ejemplo: reaccionar.s3.amazonaws.com
  • Vaya a la pestaña Páginas de error , haga clic en Crear respuesta de error personalizada :
    • Código de error HTTP : 403: Prohibido (404: No encontrado, en el caso de un sitio web estático S3)
    • Personalizar respuesta de error : Sí
    • Ruta de la página de respuesta : /index.html
    • Código de respuesta HTTP : 200: Aceptar
    • Haga clic en crear
lenaten avatar Feb 27 '2016 17:02 lenaten

La forma en que pude hacer que esto funcionara es la siguiente:

En la sección Editar reglas de redireccionamiento de la Consola S3 para su dominio, agregue las siguientes reglas:

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

Esto redirigirá todas las rutas que resulten en un 404 no encontrado a su dominio raíz con una versión hash-bang de la ruta. Por lo tanto http://example.com/posts, se redirigirá a http://example.com/#!/postssiempre que no haya ningún archivo en /posts.

Sin embargo, para usar HTML5 pushStates, debemos tomar esta solicitud y establecer manualmente el pushState adecuado según la ruta hash-bang. Así que agrega esto al principio de tu index.htmlarchivo:

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

Esto toma el hash y lo convierte en un pushState HTML5. A partir de este momento, puede usar pushStates para tener rutas que no sean hash-bang en su aplicación.

Mark Nutter avatar Jun 01 '2013 21:06 Mark Nutter

Hay algunos problemas con el enfoque basado en S3/Redirect mencionado por otros.

  1. Se producen múltiples redirecciones a medida que se resuelven las rutas de su aplicación. Por ejemplo: www.example.com/path/for/testes redirigido comowww.example.com/#/path/for/test
  2. Hay un parpadeo en la barra de URL a medida que #va y viene debido a la acción de su marco SPA.
  3. El SEO se ve afectado porque: '¡Oye! Es Google forzando su mano en las redirecciones.
  4. El soporte de Safari para tu aplicación se va a pique.

La solucion es:

  1. Asegúrese de tener configurada la ruta de índice para su sitio web. Mayormente esindex.html
  2. Eliminar reglas de enrutamiento de las configuraciones de S3
  3. Coloque un CloudFront frente a su depósito S3.
  4. Configure reglas de página de error para su instancia de CloudFront. En las reglas de error especifique:
  • Código de error HTTP: 404 (y 403 u otros errores según sea necesario)
  • Error de almacenamiento en caché TTL mínimo (segundos): 0
  • Personalizar respuesta: Sí
  • Ruta de la página de respuesta:/index.html
  • Código de respuesta HTTP: 200
  1. Para las necesidades de SEO + asegurarse de que index.htmlno se almacene en caché, haga lo siguiente:
  • Configure una instancia EC2 y configure un servidor Nginx.
  • Asigne una IP pública a su instancia EC2.
  • Cree un ELB que tenga la instancia EC2 que creó como instancia
  • Debería poder asignar el ELB a su DNS.
  • Ahora, configure su servidor Nginx para hacer lo siguiente: Proxy_pass todas las solicitudes a su CDN ( index.htmlsolo para servir otros activos directamente desde su CloudFront) y para los robots de búsqueda, redirigir el tráfico según lo estipulado por servicios como Prerender.io.

Puedo ayudar con más detalles con respecto a la configuración de Nginx, solo deje una nota. Lo he aprendido de la manera más difícil.

Una vez que se actualice la distribución del frente de la nube. Invalide su caché de CloudFront una vez para estar en el modo original. Presione la URL en el navegador y todo debería estar bien.

moha297 avatar Feb 12 '2016 04:02 moha297

Es tangencial, pero aquí hay un consejo para aquellos que usan la biblioteca React Router de Rackt con historial de navegador (HTML5) y desean alojar en S3.

Supongamos que un usuario visita /foo/bearsu sitio web estático alojado en S3. Dada la sugerencia anterior de David , las reglas de redireccionamiento los enviarán a . Si su aplicación se creó utilizando el historial del navegador, esto no servirá de mucho. Sin embargo, su aplicación está cargada en este punto y ahora puede manipular el historial./#/foo/bear

Al incluir el historial de Rackt en nuestro proyecto (consulte también Uso de historiales personalizados del proyecto React Router), puede agregar un oyente que conozca las rutas del historial hash y reemplazar la ruta según corresponda, como se ilustra en este ejemplo:

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'))
);

Recordar:

  1. La regla de redireccionamiento S3 de David dirigirá /foo/beara /#/foo/bear.
  2. Su aplicación se cargará.
  3. El oyente histórico detectará la #/foo/bearnotación histórica.
  4. Y reemplace la historia con el camino correcto.

LinkLas etiquetas funcionarán como se esperaba, al igual que todas las demás funciones del historial del navegador. El único inconveniente que he notado es la redirección intersticial que se produce en la solicitud inicial.

Esto se inspiró en una solución para AngularJS y sospecho que podría adaptarse fácilmente a cualquier aplicación.

Michael Ahlers avatar Jan 23 '2016 00:01 Michael Ahlers

Ahora puedes hacer esto con Lambda@Edge para reescribir las rutas.

Aquí hay una función lambda@Edge que funciona:

  1. Cree una nueva función Lambda, pero utilice uno de los Blueprints preexistentes en lugar de una función en blanco.
  2. Busque "cloudfront" y seleccione generación de respuesta de cloudfront en los resultados de la búsqueda.
  3. Después de crear la función, reemplace el contenido con lo siguiente. También tuve que cambiar el tiempo de ejecución del nodo a 10.x porque cloudfront no admitía el nodo 12 en el momento de escribir este artículo.
'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);
};

En sus comportamientos frente a la nube, los editará para agregar una llamada a esa función lambda en "Solicitud de espectador". ingrese la descripción de la imagen aquí

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

Loren avatar Feb 19 '2020 16:02 Loren