11 votes

Hébergement de plusieurs applications web SPA sur S3 + Cloudfront sous la même URL

J'ai deux applications web statiques (create-react-apps) qui sont actuellement dans deux buckets S3 séparés. Les deux buckets sont configurés pour la lecture publique + l'hébergement web statique, et la visite de leurs URLs hébergées sur S3 affiche correctement les sites.

Bucket 1 - First App:
   index.html
   static/js/main.js

Bucket 2 - Second App:
   /secondapp/
       index.html
       static/js/main.js

J'ai mis en place un seul Cloudfront pour cela - L'origine par défaut du Cloudfront se charge FirstApp de manière à ce que www.mywebsite.com charge le fichier index.html par défaut.

Pour les SecondApp J'ai configuré un comportement de mise en cache de sorte que le modèle de chemin secondapp/* pointe vers l'URL du seau SecondApp.

Dans mon navigateur, lorsque je visite www.mywebsite.com/secondapp/ il affiche correctement la deuxième application web.

Cependant, si j'omets la barre oblique finale, je vois la première application, ce qui n'est pas souhaitable. Si je visite www.mywebsite.com/secondapp/something Je suis également informé de la première application, ce qui n'est pas non plus souhaitable. (Je veux qu'elle charge le fichier .html de secondapp )

Les deux applications sont configurées pour utiliser html5 push state via react-router-dom.

Ce que je souhaite, c'est que la visite du site suivant affiche le bon site/bouquet :

www.mywebsite.com - En cours de travail

www.mywebsite.com/secondapp/ - En cours de travail

www.mywebsite.com/secondapp - (Sans barre oblique) Ne fonctionne pas, affiche Première application

www.mywebsite.com/secondapp/something_else - Ne fonctionne pas, montre First App

Comment puis-je obtenir le comportement souhaité ?

Merci de votre attention !

13voto

SRandazzo Points 264

Après avoir fait des recherches sur ce problème, j'ai pu le résoudre en utilisant lambda@edge ( https://aws.amazon.com/lambda/edge/ )

En déployant une simple fonction javascript pour router des chemins spécifiques vers le bucket s3 désiré, nous sommes en mesure d'obtenir une configuration de routage de type nginx. La fonction se trouve sur lambda@edge sur notre CDN Cloudfront, ce qui signifie que vous pouvez spécifier quand il est déclenché. Pour nous, il s'agit de la "demande d'origine"

Ma configuration est la suivante :

  • J'ai utilisé un seul bucket s3, et j'ai déployé ma seconde application dans un sous-dossier "second-app"
  • J'ai créé une nouvelle fonction Lambda, hébergée sur "U.S. East N Virginia". La région est importante ici, car vous ne pouvez héberger une fonction Lambda sur un @edge que dans cette région.
  • Voir ci-dessous pour la fonction Lambda proprement dite
  • Une fois créé, allez dans votre configuration CloudFront et allez dans "Behaviors > Select the Default (*) path pattern and click Edit" (Comportements > Sélectionner le modèle de chemin par défaut (*) et cliquer sur Edit)
  • Descendez jusqu'au bas de la page où vous trouverez "Lambda Function Associations" (associations de fonctions lambda)
  • Sélectionnez "Demande d'origine" dans le menu déroulant
  • Saisissez l'adresse de votre fonction lambda ( arn:aws:lambda:us-east-1:12345667890:function:my-function-name )

Voici un exemple de la fonction lambda que j'ai utilisée.

var path = require('path');

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;

  const parsedPath = path.parse(request.uri);

  // If there is no extension present, attempt to rewrite url
  if (parsedPath.ext === '') {
    // 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(/second-app.*/, 'second-app/index.html');

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;
  }
  // If an extension was not present, we are trying to load static access, so allow the request to proceed
  // Return to CloudFront
  return callback(null, request);
};

Voici les ressources que j'ai utilisées pour cette solution :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X