amazon-web-services redirect amazon-s3 routing pushstate

amazon web services - Sitio web estático de S3 Hospedaje Route All Paths to Index.html



amazon-web-services redirect (12)

Estoy usando S3 para alojar una aplicación de JavaScript que utilizará HTML5 pushStates. El problema es que si el usuario marca cualquiera de las URL, no resolverá nada. Lo que necesito es la capacidad de tomar todas las solicitudes de URL y publicar el índice raíz.html en mi categoría S3, en lugar de solo hacer una redirección completa. Entonces mi aplicación javascript podría analizar la URL y servir la página correcta.

¿Hay alguna forma de decirle a S3 que sirva el index.html para todas las solicitudes de URL en lugar de hacer redirecciones? Esto sería similar a la configuración de Apache para manejar todas las solicitudes entrantes mediante la publicación de un solo index.html como en este ejemplo: https://stackoverflow.com/a/10647521/1762614 . Realmente me gustaría evitar ejecutar un servidor web solo para manejar estas rutas. Hacer todo desde S3 es muy atractivo.


Es muy fácil resolverlo sin url hacks, con la ayuda de CloudFront.

  • Crear cubo S3, por ejemplo: reaccionar
  • Cree distribuciones CloudFront con estas configuraciones:
    • Objeto raíz predeterminado : index.html
    • Nombre de dominio de origen : dominio de segmento S3, por ejemplo: react.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 del 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: OK
    • Haga clic en Crear

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

Supongamos que un usuario visita /foo/bear en su sitio web estático alojado en S3. Dada David''s sugerencia anterior David''s , las reglas de redireccionamiento los enviarán a /#/foo/bear . Si su aplicación está construida usando 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.

Incluyendo el history Rackt en nuestro proyecto (consulte también Uso de historias personalizadas del proyecto React Router), puede agregar un oyente que conozca las rutas del historial de hash y reemplace 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 redirección S3 de David dirigirá /foo/bear a /#/foo/bear .
  2. Su aplicación se cargará.
  3. El oyente del historial detectará la notación del historial #/foo/bear .
  4. Y reemplace el historial con la ruta correcta.

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

Esto fue inspirado por una solución para AngularJS , y sospecho que podría adaptarse fácilmente a cualquier aplicación.


Esta es la solución más elegante que encontré: use el módulo del enrutador de la aplicación con un comodín de redirección.

{ path: ''**'', redirectTo: '''' }

Luego, como se menciona en las innumerables publicaciones anteriores, asegúrese de estar redirigiendo los errores 404/403 a index.html con el estado 200. El problema es que esto da como resultado una actualización del navegador cargando la href base como (href + ruta previa). Si estuviera viendo la vista del enrutador en

www.my-app.com/home entonces la actualización mostrará

www.my-app.com/home/home

Para quitar la ruta de ruta duplicada, use el módulo APP_BASE_HREF para reasignar el href de la base del navegador como este

Si necesita conservar el primer parámetro url, añada varios resultados de la división ''/'' .

El navegador acierta a su redireccionamiento de SPA para www.your-app.com/home/home ahora reemplazará la URL con www.your-app.com/home y la aplicación se comportará como se espera de su configuración de enrutamiento en la aplicación


Estaba buscando el mismo tipo de problema. Terminé usando una combinación de las soluciones sugeridas descritas arriba.

Primero, tengo un cubo s3 con varias carpetas, cada carpeta representa un sitio web de reacción / reducción. También uso Cloudfront para la invalidación de caché.

Así que tuve que usar reglas de enrutamiento para soportar 404 y redirigirlas a una configuración 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>

En mi código js, ​​necesitaba manejarlo con una configuración baseName para reaccionar-enrutador. Antes que nada, asegúrate de que tus dependencias sean interoperables, tenía instalado el history==4.0.0 que era incompatible con react-router==3.0.1 .

Mis dependencias son:

  • "historia": "3.2.0",
  • "reaccionar": "15.4.1",
  • "react-redux": "4.4.6",
  • "reaccionar-enrutador": "3.0.1",
  • "reaccionar-enrutador-redux": "4.0.7",

history.js un archivo history.js para cargar el historial:

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;

Este fragmento de código permite manejar el 404 enviado por el servidor con un hash, y reemplazarlos en el historial para cargar nuestras rutas.

Ahora puede usar este archivo para configurar su tienda y su archivo Root.

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 eso ayude. Notarás que con esta configuración utilizo el inyector redux y un inyector home saws sagas para cargar Javascript de manera asíncrona a través del enrutamiento. No te preocupes con estas líneas.


Estaba buscando una respuesta a esto yo mismo. Parece que S3 solo admite redireccionamientos, no puede simplemente reescribir la URL y devolver de forma silenciosa un recurso diferente. Estoy considerando usar mi script de compilación para simplemente hacer copias de mi index.html en todas las ubicaciones de ruta requeridas. Quizás eso también funcione para ti.


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

  1. Los redireccionamientos múltiples ocurren cuando se resuelven las rutas de acceso de su aplicación. Por ejemplo: www.myapp.com/path/for/test se redirecciona como www.myapp.com/#/path/for/test
  2. Hay un parpadeo en la barra de direcciones ya que el ''#'' aparece y desaparece debido a la acción de su marco SPA.
  3. El seo se ve afectado porque - ''¡Oye! Su google forzando su mano en redirecciones ''
  4. El soporte de Safari para su aplicación va por un lanzamiento.

La solucion es:

  1. Asegúrese de tener la ruta de índice configurada para su sitio web. En su mayoría es index.html
  2. Elimine las reglas de enrutamiento de las configuraciones S3
  3. Pon un Cloudfront en frente de tu cubo 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 la necesidad)
    • Error Caching TTL mínimo (segundos): 0
    • Personalizar la respuesta: sí
    • Ruta de la página de respuesta: /index.html
    • Código de respuesta HTTP: 200

5. Para las necesidades de SEO + asegurándose de que su index.html no caché, haga lo siguiente:

  • Configure una instancia EC2 y configure un servidor nginx.
  • Asigne una IP pública a su instancia de 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_pasar todas las solicitudes a su CDN (solo para index.html, servir otros activos directamente desde su nube) y para los bots de búsqueda, redireccionar el tráfico según lo estipulado por servicios como Prerender.io

Puedo ayudarlo en más detalles con respecto a la configuración de nginx, solo deje una nota. Lo aprendí de la manera difícil.

Una vez que la distribución de la distribución de la nube frente. Invalida tu caché frente a la nube una vez para estar en el modo prístino. Pulse la url en el navegador y todo debería ser bueno.


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

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

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

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

Sin embargo, para utilizar HTML5 pushStates, debemos realizar esta solicitud y establecer manualmente el estado de push adecuado en función de la ruta hash-bang. Así que agrega esto a la parte superior de tu archivo index.html:

<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 punto, puedes usar pushStates para tener rutas que no sean hash-bang en tu aplicación.


La solución Mark no está mal, pero hay una solución aún más simple para eso. En las propiedades del depósito en el documento de error solo use el mismo archivo que el documento de índice . Los frameworks de JavaScript como Backbone, AngularJS, etc., funcionarán de esta manera y la actualización de la página será totalmente compatible.


La solución más sencilla para hacer que la aplicación Angular 2+ servida desde Amazon S3 y las URL directas funcione es especificar index.html como documentos de índice y de error en la configuración del segmento S3.


Me encontré con el mismo problema hoy, pero la solución de @ Mark-Nutter estaba incompleta para eliminar el hashbang de mi aplicación angularjs.

De hecho, tiene que ir a Editar Permisos , hacer clic en Agregar más permisos y luego agregar la Lista correcta en su cubo a todos. Con esta configuración, AWS S3 ahora podrá devolver el error 404 y luego la regla de redirección atrapará correctamente el caso.

Solo así:

Y luego puede ir a Editar Reglas de Redirección y agregar esta regla:

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

Aquí puede reemplazar el nombre de dominio subdomain.domain.fr con su dominio y KeyPrefix #! / Si no utiliza el método hashbang para fines de SEO.

Por supuesto, todo esto solo funcionará si ya has configurado el modo html5 en tu aplicación angular.

$locationProvider.html5Mode(true).hashPrefix(''!'');


Veo 4 soluciones a este problema. Los primeros 3 ya fueron cubiertos en las respuestas y el último es mi contribución.

  1. Establezca el documento de error en index.html.
    Problema : el cuerpo de respuesta será correcto, pero el código de estado será 404, lo que perjudica a SEO.

  2. Establezca las reglas de redirección.
    Problema : URL contaminada con #! y la página parpadea cuando se carga.

  3. Configure CloudFront.
    Problema : todas las páginas devolverán 404 desde el origen, por lo que deberá elegir si no va a almacenar en caché nada (TTL 0 como se sugiere) o si va a guardar en caché y tendrá problemas al actualizar el sitio.

  4. Predetermina todas las páginas
    Problema : trabajo adicional para preengañar páginas, especialmente cuando las páginas cambian con frecuencia. Por ejemplo, un sitio web de noticias.

Mi sugerencia es usar la opción 4. Si predescribe todas las páginas, no habrá errores 404 para las páginas esperadas. La página se cargará bien y el marco tomará el control y actuará normalmente como un SPA. También puede configurar el documento de error para que muestre una página genérica error.html y una regla de redireccionamiento para redirigir los errores 404 a una página 404.html (sin el hashbang).

En cuanto a los 403 errores prohibidos, no los dejo pasar. En mi aplicación, considero que todos los archivos dentro del contenedor de host son públicos y configuré esto con la opción de todos con el permiso de lectura . Si su sitio tiene páginas que son privadas, dejar que el usuario vea el diseño HTML no debería ser un problema. Lo que necesita proteger son los datos y esto se hace en el back-end.

Además, si tiene activos privados, como fotos de usuario, puede guardarlos en otro cubo. Porque los activos privados necesitan el mismo cuidado que los datos y no se pueden comparar con los archivos de activos que se usan para alojar la aplicación.


ya que el problema todavía está allí, pensé en tirar otra solución. Mi caso fue que quería implementar automáticamente todas las solicitudes de extracción a s3 para probar antes de fusionarlas haciéndolas accesibles en [mydomain] / pull-requests / [pr number] /
(por ejemplo, www.example.com/pull-requests/822/)

A mi leal saber y entender, los escenarios de reglas que no sean de s3 permitirían tener múltiples proyectos en un cubo utilizando el enrutamiento html5, por lo que aunque la sugerencia más votada funciona para un proyecto en la carpeta raíz, no sirve para múltiples proyectos en subcarpetas propias.

Así que apunté mi dominio a mi servidor donde las siguientes configuraciones de nginx hicieron el trabajo

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; }

intenta obtener el archivo y, si no se encuentra, asume que es ruta html5 y lo intenta. Si tienes una página angular 404 para rutas no encontradas, nunca llegarás a @not_found y obtendrás la página angular 404 devuelta en lugar de los archivos no encontrados, que podría corregirse con alguna regla si @get_routes o algo así.

Debo decir que no me siento demasiado cómodo en el área de configuración de nginx y uso de expresiones regulares para el caso, hice que funcionara con un poco de prueba y error, así que mientras esto funcione, estoy seguro de que hay margen de mejora y por favor comparta sus ideas. .

Nota : elimine las reglas de redirección de s3 si las tiene en la configuración de S3.

y por cierto funciona en Safari