Hébergement de sites Web statiques S3 Route tous les chemins vers Index.html

250

J'utilise S3 pour héberger une application javascript qui utilisera les pushStates HTML5. Le problème est que si l'utilisateur met en signet l'une des URL, il ne résoudra rien. Ce dont j'ai besoin, c'est de pouvoir prendre toutes les demandes d'URL et servir le root index.html dans mon compartiment S3, plutôt que de simplement faire une redirection complète. Ensuite, mon application javascript pourrait analyser l'URL et diffuser la page appropriée.

Existe-t-il un moyen de dire à S3 de servir le fichier index.html pour toutes les demandes d'URL au lieu de faire des redirections? Cela serait similaire à la configuration d'apache pour gérer toutes les demandes entrantes en servant un seul index.html comme dans cet exemple: https://stackoverflow.com/a/10647521/1762614 . Je voudrais vraiment éviter d'exécuter un serveur Web juste pour gérer ces routes. Tout faire depuis S3 est très attrayant.

Mark Nutter
la source
Avez-vous trouvé une solution à cela?
w2lame

Réponses:

302

Il est très facile de le résoudre sans piratage d'URL, avec l'aide de CloudFront.

  • Créez un compartiment S3, par exemple: réagissez
  • Créez des distributions CloudFront avec ces paramètres:
    • Objet racine par défaut : index.html
    • Nom de domaine d'origine : domaine de compartiment S3, par exemple: react.s3.amazonaws.com
  • Accédez à l' onglet Pages d'erreur , cliquez sur Créer une réponse d'erreur personnalisée :
    • Code d'erreur HTTP : 403: interdit (404: introuvable, dans le cas d'un site Web statique S3)
    • Personnaliser la réponse aux erreurs : Oui
    • Chemin de la page de réponses : /index.html
    • Code de réponse HTTP : 200: OK
    • Cliquez sur Créer
lenaten
la source
8
Merci. La meilleure réponse jusqu'à présent.
jgb
et ce qui n'est pas si évident, vous gardez la position pour pouvoir faire un routage "naturel".
Lukasz Marek Sielski
5
cela a fonctionné comme un charme pour moi, seul le code d'erreur personnalisé dont j'avais besoin était 404, pas 403
Jeremy S.
4
Un peu de piratage, mais fonctionne très bien :) Ce serait bien si CloudFront nous permettait simplement de mapper une plage de chemins vers un fichier S3 (sans redirection).
Bob
3
Ça ne marche pas pour moi. Cette solution redirige toujours vers la page d'accueil et non vers les pages correctes ...
Jim
201

La façon dont j'ai pu faire fonctionner cela est la suivante:

Dans la section Modifier les règles de redirection de la console S3 pour votre domaine, ajoutez les règles suivantes:

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

Cela redirigera tous les chemins qui se traduisent par un 404 introuvable sur votre domaine racine avec une version hachée du chemin. Alors http://yourdomainname.com/posts redirigera à http://yourdomainname.com/#!/posts fourni il n'y a pas de fichier à / messages.

Cependant, pour utiliser les pushStates HTML5, nous devons prendre cette demande et établir manuellement le pushState approprié en fonction du chemin de hachage. Ajoutez donc ceci en haut de votre fichier index.html:

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

Cela saisit le hachage et le transforme en un pushState HTML5. À partir de ce moment, vous pouvez utiliser pushStates pour avoir des chemins non-hash-bang dans votre application.

Mark Nutter
la source
4
Cette solution fonctionne très bien! En fait, angularjs effectuera automatiquement l'historique pushState si le mode html est configuré.
wcandillon
1
Cela échouera avec l'ancienne version d'IE si vous avez des paramètres GET inclus dans vos URL, n'est-ce pas? Comment contournez-vous ce problème?
clexmond
3
Merci! Cela a bien fonctionné pour moi sur l'épine dorsale avec un petit ajustement. J'ai ajouté une vérification pour les anciens navigateurs: <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
Réussi avec react-routercette solution en utilisant les pushStates HTML5 et<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
Felix D.
5
Cela ne fonctionne pas en safari et c'est un gros problème avec la stratégie de déploiement. Écrire un petit js pour rediriger est une sorte d'approche minable. De plus, le nombre de redirections est également un problème. J'essaie de comprendre s'il existe un moyen pour toutes les URL S3 de pointer vers index.html toujours.
moha297
129

Il y a peu de problèmes avec l'approche basée sur S3 / Redirect mentionnée par d'autres.

  1. Les redirections multiples se produisent lorsque les chemins de votre application sont résolus. Par exemple: www.myapp.com/path/for/test est redirigé vers www.myapp.com/#/path/for/test
  2. Il y a un scintillement dans la barre d'URL lorsque le «#» va et vient en raison de l'action de votre infrastructure SPA.
  3. Le seo est impacté parce que - 'Hé! Son google forçant sa main sur les redirections '
  4. La prise en charge de Safari pour votre application va de pair.

La solution est:

  1. Assurez-vous que la route d'index est configurée pour votre site Web. C'est surtout index.html
  2. Supprimer les règles de routage des configurations S3
  3. Placez un Cloudfront devant votre compartiment S3.
  4. Configurez les règles de page d'erreur pour votre instance Cloudfront. Dans les règles d'erreur, spécifiez:

    • Code d'erreur HTTP: 404 (et 403 ou autres erreurs selon les besoins)
    • Erreur de mise en cache TTL minimum (secondes): 0
    • Personnaliser la réponse: oui
    • Chemin de la page de réponses: /index.html
    • Code de réponse HTTP: 200

      1. Pour les besoins de référencement + en vous assurant que votre index.html ne cache pas, procédez comme suit:
    • Configurez une instance EC2 et configurez un serveur nginx.

    • Attribuez une adresse IP publique à votre instance EC2.
    • Créer un ELB contenant l'instance EC2 que vous avez créée en tant qu'instance
    • Vous devriez pouvoir attribuer l'ELB à votre DNS.
    • Maintenant, configurez votre serveur nginx pour faire les choses suivantes: Proxy_pass toutes les demandes à votre CDN (pour index.html uniquement, servir d'autres actifs directement à partir de votre cloudfront) et pour les robots de recherche, rediriger le trafic comme stipulé par des services comme Prerender.io

Je peux vous aider dans plus de détails en ce qui concerne la configuration de nginx, laissez simplement une note. Je l'ai appris à la dure.

Une fois la mise à jour de la distribution cloud front. Invalidez une fois votre cache cloudfront pour être en mode vierge. Appuyez sur l'URL dans le navigateur et tout devrait être bon.

moha297
la source
6
puisque S3 répond avec un 403 interdit lorsqu'un fichier n'existe pas, je pense que l'étape 4 ci-dessus doit également être dupliquée pour le code d'erreur Http 403
Andreas
4
Pour moi, c'est la seule réponse qui se traduit par un comportement attendu (accepté)
mabe.berlin
1
@ moha297 au point 5, configurez-vous essentiellement votre site pour qu'il récupère à partir de nginx qui procède ensuite à un proxy à partir du CDN (sauf pour index.html et les requêtes du robot)? Si tel est le cas, ne perdriez-vous pas l'avantage des serveurs de périphérie CDN?
Rahul Patel
2
@ moha297 pouvez-vous s'il vous plaît expliquer ce commentaire: "Vous ne devriez jamais servir index.html à partir d'un CDN"? Je ne vois pas le problème avec le service index.html de S3 avec CloudFront.
Carl G
1
Voir stackoverflow.com/a/10622078/4185989 pour plus d'informations sur la façon dont un TTL de 0 est traité (version courte: il est mis en cache par Cloudfront mais une If-Modified-Sincedemande GET est envoyée à l'origine) - peut être une considération utile pour les personnes qui ne veulent pas configurer un serveur comme à l'étape 5.
jmq
18

C'est tangentiel, mais voici un conseil pour ceux qui utilisent la bibliothèque React Router de Rackt avec l' historique du navigateur (HTML5) qui souhaitent héberger sur S3.

Supposons qu'un utilisateur visite /foo/bearvotre site Web statique hébergé par S3. Compte tenu de la suggestion précédente de David , les règles de redirection les enverront à /#/foo/bear. Si votre application est construite à l'aide de l'historique du navigateur, cela ne fera pas grand chose. Cependant, votre application est chargée à ce stade et elle peut désormais manipuler l'historique.

En incluant l' historique Rackt dans notre projet (voir également Utilisation d'histoires personnalisées du projet React Router), vous pouvez ajouter un écouteur qui connaît les chemins de l'historique de hachage et remplacer le chemin si nécessaire, comme illustré dans cet exemple:

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

Récapituler:

  1. La règle de redirection S3 de David dirigera /foo/bearvers /#/foo/bear.
  2. Votre application va se charger.
  3. L'écouteur d'historique détectera la #/foo/bearnotation d'historique.
  4. Et remplacez l'historique par le chemin correct.

Linkles balises fonctionneront comme prévu, comme toutes les autres fonctions d'historique du navigateur. Le seul inconvénient que j'ai remarqué est la redirection interstitielle qui se produit à la demande initiale.

Cela a été inspiré par une solution pour AngularJS , et je soupçonne qu'il pourrait être facilement adapté à n'importe quelle application.

Michael Ahlers
la source
2
Cela m'a aidé Michael, merci! Vous voudrez peut-être changer votre référence de l'historique et utiliser simplement BrowserHistory. iebrowserHistory.listen
Marshall Moutenot
Vous êtes les bienvenus! Heureux de vous aider. En outre, d'accord, et pour ce cas d'utilisation particulier, j'ai mis à jour l'extrait de code pour résoudre un avertissement de dépréciation de React Router.
Michael Ahlers
Avec la sortie de react-router v3.0.0, cela ne fonctionne pas, car react-router v3.0.0 utilise History v3.0.0
Varand Pezeshkian
Une idée comment empêcher la boucle d'appel infinie history.listen? Causé en remplaçant le chemin, je suppose.
Mirko Flyktman
14

Je vois 4 solutions à ce problème. Les 3 premiers étaient déjà couverts dans les réponses et le dernier est ma contribution.

  1. Définissez le document d'erreur sur index.html.
    Problème : le corps de la réponse sera correct, mais le code d'état sera 404, ce qui nuit au référencement.

  2. Définissez les règles de redirection.
    Problème : l'URL polluée par #!et la page clignote lors du chargement.

  3. Configurez CloudFront.
    Problème : toutes les pages renverront 404 d'origine, vous devez donc choisir si vous ne mettrez rien en cache (TTL 0 comme suggéré) ou si vous mettrez en cache et rencontrez des problèmes lors de la mise à jour du site.

  4. Prérender toutes les pages.
    Problème : travail supplémentaire pour les pages de pré-rendu, spécialement lorsque les pages changent fréquemment. Par exemple, un site Web d'actualités.

Ma suggestion est d'utiliser l'option 4. Si vous pré-rendez toutes les pages, il n'y aura pas d'erreurs 404 pour les pages attendues. La page se chargera correctement et le framework prendra le contrôle et agira normalement comme un SPA. Vous pouvez également définir le document d'erreur pour afficher une page générique error.html et une règle de redirection pour rediriger les erreurs 404 vers une page 404.html (sans le hashbang).

En ce qui concerne les erreurs interdites 403, je ne les laisse pas du tout se produire. Dans mon application, je considère que tous les fichiers dans le bucket hôte sont publics et je l'ai défini avec l' option tout le monde avec l' autorisation de lecture . Si votre site a des pages privées, laisser l'utilisateur voir la mise en page HTML ne devrait pas être un problème. Ce que vous devez protéger, ce sont les données et cela se fait dans le backend.

De plus, si vous possédez des actifs privés, comme des photos d'utilisateurs, vous pouvez les enregistrer dans un autre compartiment. Parce que les actifs privés nécessitent le même soin que les données et ne peuvent pas être comparés aux fichiers d'actifs utilisés pour héberger l'application.

Zanon
la source
1
et votre site a un excellent exemple d'utilisation avec pré-rendu pour toutes les pages. zanon.io/posts/… .- Merci
frekele
Cette quatrième approche concerne-t-elle l'utilisateur rechargeant l'URL pushState? Il gère très bien la navigation mais lors d'un rechargement, il atteindra toujours le serveur.
Alpha
@Alpha, je ne sais pas si j'ai bien compris votre question, mais lors d'un rechargement, il s'agirait d'une nouvelle demande. S3 recevrait la demande et retournerait à nouveau la page pré-rendue. Il n'y a pas de serveur dans ce cas.
Zanon
@Zanon Ah, je pense que je comprends. Je pensais que c'était destiné à mettre en cache les pages pré-rendues et à éviter d'aller chercher les ressources inexistantes S3. Cela laisserait de côté les itinéraires qui ont des éléments dynamiques, non?
Alpha
1
@Zanon Je comprends enfin - merci! Oui, c'est ce que je voulais dire. :)
Alpha
13

J'ai rencontré le même problème aujourd'hui, mais la solution de @ Mark-Nutter était incomplète pour supprimer le hashbang de mon application angularjs.

En fait, vous devez aller dans Modifier les autorisations , cliquer sur Ajouter plus d'autorisations , puis ajouter la bonne liste sur votre compartiment à tout le monde. Avec cette configuration, AWS S3 sera désormais en mesure de renvoyer une erreur 404, puis la règle de redirection interceptera correctement le cas.

Juste comme ça : entrez la description de l'image ici

Et puis vous pouvez aller dans Modifier les règles de redirection et ajouter cette règle:

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

Ici, vous pouvez remplacer le nom d' hôte subdomain.domain.fr par votre domaine et le KeyPrefix #! / Si vous n'utilisez pas la méthode hashbang à des fins de référencement.

Bien sûr, tout cela ne fonctionnera que si vous avez déjà configuré html5mode dans votre application angulaire.

$locationProvider.html5Mode(true).hashPrefix('!');
davidbonachera
la source
mon seul problème avec ceci est que vous avez un flash de hashbang, que vous n'avez pas avec quelque chose comme une règle nginx. L'utilisateur est sur une page et actualise: / produits / 1 -> #! / Produits / 1 -> / produits / 1
Intellix
1
Je pense que vous devriez ajouter une règle pour une erreur 403 plutôt que d'accorder des autorisations de liste à tout le monde.
Hamish Moffatt
11

La solution la plus simple pour faire fonctionner l'application Angular 2+ à partir d'Amazon S3 et des URL directes est de spécifier index.html à la fois comme documents d'index et d'erreur dans la configuration du compartiment S3.

entrez la description de l'image ici

Sergey Kandaurov
la source
11
C'est la même réponse que cette réponse fortement sous-votée . Cela fonctionne bien, mais uniquement pour bodyla réponse. Le code d'état sera 404 et cela nuira au référencement.
Zanon
Parce que cela ne fonctionne que bodysi vous avez des scripts que vous importez dans le headils ne fonctionneront pas lorsque vous frappez directement l'un des sous-itinéraires sur votre site Web
Mohamed Hajr
4

comme le problème est toujours là, j'ai pensé proposer une autre solution. Mon cas était que je voulais déployer automatiquement toutes les demandes d'extraction vers s3 pour les tester avant de les fusionner en les rendant accessibles sur [mon domaine] / pull-demandes / [numéro pr] /
(ex. Www.example.com/pull-requests/822/ )

À ma connaissance, aucun scénario de règles s3 ne permettrait d'avoir plusieurs projets dans un seul compartiment en utilisant le routage html5, alors que la suggestion la plus votée fonctionne pour un projet dans le dossier racine, mais pas pour plusieurs projets dans ses propres sous-dossiers.

J'ai donc pointé mon domaine vers mon serveur où la configuration nginx suivante a fait le travail

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

il essaie d'obtenir le fichier et s'il n'est pas trouvé suppose qu'il s'agit de la route html5 et essaie cela. Si vous avez une page angulaire 404 pour les itinéraires non trouvés, vous n'obtiendrez jamais à @not_found et vous obtiendrez une page 404 angulaire retournée au lieu de fichiers non trouvés, qui pourrait être corrigée avec une règle if dans @get_routes ou quelque chose.

Je dois dire que je ne me sens pas trop à l'aise dans le domaine de la configuration de nginx et de l'utilisation d'expressions rationnelles, d'ailleurs, j'ai réussi à le faire avec quelques essais et erreurs, alors que cela fonctionne, je suis sûr qu'il y a place à amélioration et s'il vous plaît partagez vos réflexions .

Remarque : supprimez les règles de redirection s3 si vous les aviez dans la configuration S3.

et btw fonctionne dans Safari

Andrew Arnautov
la source
salut .. merci pour la solution ... où placez-vous ce fichier conf nginx pour le déploiement s3. est-ce la même chose que élastique beanstalk où j'ai besoin de créer le dossier .exextensions et de le mettre dans le fichier proxy.config?
user3124360
@ user3124360 Je ne suis pas sûr de l'élastic beanstack, mais dans mon cas, je pointe mon nom de domaine vers l'instance ec2 et y ai la configuration nginx. Ainsi la demande va CLIENT -> DNS -> EC2 -> S3 -> CLIENT.
Andrew Arnautov
ouais je fais quelque chose de très similaire ... avec nginx config ici github.com/davezuko/react-redux-starter-kit/issues/1099 ... merci d'avoir posté votre fichier conf .. je vois comment développer cet EC2 -> Connexion S3 maintenant
user3124360
3

Je cherchais le même genre de problème. J'ai fini par utiliser un mélange des solutions suggérées décrites ci-dessus.

Tout d'abord, j'ai un compartiment s3 avec plusieurs dossiers, chaque dossier représente un site Web react / redux. J'utilise également cloudfront pour l'invalidation du cache.

J'ai donc dû utiliser les règles de routage pour prendre en charge 404 et les rediriger vers une configuration de hachage:

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

Dans mon code js, j'avais besoin de le gérer avec une baseNameconfiguration pour react-router. Tout d'abord, assurez-vous que vos dépendances sont interopérables, j'avais installé une version history==4.0.0incompatible avec react-router==3.0.1.

Mes dépendances sont:

  • "histoire": "3.2.0",
  • "réagir": "15.4.1",
  • "react-redux": "4.4.6",
  • "react-router": "3.0.1",
  • "react-router-redux": "4.0.7",

J'ai créé un history.jsfichier pour l'historique de chargement:

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;

Ce morceau de code permet de gérer les 404 envoyés par le serveur avec un hachage, et de les remplacer dans l'historique pour charger nos routes.

Vous pouvez maintenant utiliser ce fichier pour configurer votre magasin et votre fichier racine.

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;

J'espère que ça aide. Vous remarquerez qu'avec cette configuration, j'utilise un injecteur redux et un injecteur sagas homebrew pour charger javascript de manière asynchrone via le routage. Ne vous occupez pas de ces lignes.

Guillaume Cisco
la source
3

Vous pouvez maintenant le faire avec Lambda @ Edge pour réécrire les chemins

Voici une fonction lambda @ Edge fonctionnelle:

  1. Créez une nouvelle fonction Lambda, mais utilisez l'un des Blueprints préexistants au lieu d'une fonction vide.
  2. Recherchez «cloudfront» et sélectionnez cloudfront-response-generation dans les résultats de la recherche.
  3. Après avoir créé la fonction, remplacez le contenu par ce qui suit. J'ai également dû changer le runtime du noeud en 10.x car cloudfront ne supportait pas le noeud 12 au moment de l'écriture.
'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);
};

Dans vos comportements cloudfront, vous les modifierez pour ajouter un appel à cette fonction lambda sur "Viewer Request" entrez la description de l'image ici

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

Loren
la source
1
Votre exemple de code ne manque qu'une ligne:return callback(null, request);
Pherrymason
2

Si vous avez atterri ici à la recherche d'une solution qui fonctionne avec React Router et AWS Amplify Console - vous savez déjà que vous ne pouvez pas utiliser les règles de redirection CloudFront directement car Amplify Console n'expose pas CloudFront Distribution pour l'application.

Cependant, la solution est très simple - il vous suffit d'ajouter une règle de redirection / réécriture dans Amplify Console comme ceci:

Amplify Console Rewrite rule for React Router

Voir les liens suivants pour plus d'informations (et la règle de copie de la capture d'écran):

Yaro
la source
0

Je cherchais moi-même une réponse à cette question. S3 ne semble prendre en charge que les redirections, vous ne pouvez pas simplement réécrire l'URL et renvoyer silencieusement une ressource différente. J'envisage d'utiliser mon script de construction pour simplement faire des copies de mon index.html dans tous les emplacements de chemin requis. Peut-être que cela fonctionnera aussi pour vous.

Ed Thomas
la source
2
Générer des fichiers d'index pour chaque chemin m'avait aussi traversé l'esprit, mais il serait difficile d'avoir des chemins dynamiques comme example.com/groups/5/show . Si vous voyez ma réponse à cette question, je crois que cela résout le problème pour la plupart. C'est un peu un hack mais au moins ça marche.
Mark Nutter
Mieux vaut se déployer derrière un serveur nginx et renvoyer index.html pour toutes les URL entrantes. Je l'ai fait avec succès avec le déploiement Heroku des applications de braises.
moha297
-3

Juste pour mettre la réponse extrêmement simple. Utilisez simplement la stratégie d'emplacement de hachage pour le routeur si vous hébergez sur S3.

export const AppRoutingModule: ModuleWithProviders = RouterModule.forRoot (routes, {useHash: true, scrollPositionRestoration: 'enabled'});

Meester Over
la source