2
votes

Servir le fichier d'index au lieu de l'invite de téléchargement

J'ai mon site Web hébergé sur S3 avec CloudFront en tant que CDN, et j'ai besoin que ces deux URL se comportent de la même manière et servent le fichier index.html dans le répertoire:

example.com/directory example.com/directory/

Celui avec le / à la fin invite incorrectement le navigateur à télécharger un fichier de zéro octet avec un hachage aléatoire pour le nom du fichier. Sans la barre oblique, il renvoie ma page 404.

Comment puis-je obtenir les deux chemins pour livrer le fichier index.html dans le répertoire?

S'il y a un moyen, je suis "supposé" pour faire ça, super! C'est ce que j'espère, mais sinon j'essaierai probablement d'utiliser Lambda @ Edge pour faire une redirection. J'en ai besoin pour d'autres situations de toute façon, donc des instructions sur la façon de faire une redirection 301 ou 302 à partir de Lambda @ Edge seraient également utiles:)

Mise à jour (selon le commentaire de John Hanley)

curl -i https://www.example.com/directory/

HTTP/2 200 
content-type: application/x-directory
content-length: 0
date: Sat, 12 Jan 2019 22:07:47 GMT
last-modified: Wed, 31 Jan 2018 00:44:16 GMT
etag: "[id]"
accept-ranges: bytes
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 [id].cloudfront.net (CloudFront)
x-amz-cf-id: [id]

Mettre à jour

CloudFront a un ensemble de comportements, transférer http vers https et envoyer les requêtes à S3. Il a également une route d'erreur 404 sous l'onglet Erreurs.


13 commentaires

La façon dont vous vous attendez (avec / à la fin return index.html) est la façon dont les sites Web S3 fonctionnent (devraient fonctionner). Avec la barre oblique, vous devriez voir une redirection 302. Utilisez curl -i http://example.com/directory/ et mettez à jour votre question avec la réponse. Référence AWS S3: docs.aws.amazon.com/AmazonS3/latest/ dev /…


Je suppose que CloudFront aurait dû être mentionné dès le départ.


Dans CloudFront, utilisez-vous le point de terminaison du site Web (console S3 -> propriétés -> hébergement de site Web statique -> point de terminaison)? Vous devrez utiliser le point de terminaison sans la partie http: // . example.com.s3.amazonaws.com docs.aws.amazon.com/AmazonS3/latest/dev/...


@JohnHanley Yup, c'est l'URL dans mon onglet origines. L'hébergement de site Web dans S3 n'est cependant pas activé pour ce compartiment.


Dans CloudFront, quelle est la valeur de Default Root Object ?


Voici un exemple de code pour Lambda @Edge pour les redirections: docs.aws .amazon.com / AmazonCloudFront / latest / DeveloperGuide /…


Réponse StackOverflow avec exemple de code pour Lambda @Edge pour la gestion de index.html : stackoverflow.com/a/50458087/ 8016720


"Sans la barre oblique, nous obtenons le comportement correct, qui est de servir le fichier index.html dans ce répertoire." et "L'hébergement de site Web dans S3 n'est cependant pas activé pour ce compartiment. " ne peut pas être tous les deux vrais. La fonction d'hébergement de site Web S3 est requise pour que les documents d'index soient utilisés par S3 et dans le cadre du processus, S3 redirige d'abord le navigateur de / foo vers / foo / (comme tous les serveurs Web le font ou devraient le faire) avant d'afficher le objet à foo / index.html afin que les chemins relatifs dans le HTML soient corrects.


J'ai complètement oublié votre commentaire L'hébergement de site Web dans S3 n'est cependant pas activé . Ceci est nécessaire pour que la redirection se produise.


@JohnHanley J'ai activé l'hébergement de site Web S3, mais le site Web se comporte de la même manière. l'objet racine par défaut est index.html


@Costa après avoir activé la fonctionnalité d'hébergement de site Web dans S3, vous devez également définir le nom de domaine d'origine dans CloudFront sur $ {bucketname} .s3-website. $ {Bucketregion} .amazonaws.com . Avec $ {bucketname} .s3.amazonaws.com , cela ne fonctionnera pas.


Oui, et si vous faites cela, vous devez également ouvrir le seau S3 au monde, ce qui pourrait être bien.


C'est la seule option native . La gestion des documents d'index est une fonctionnalité de la fonctionnalité d'hébergement de site Web , ce qui nécessite également que les objets soient lisibles publiquement. Sinon, vous auriez besoin des fonctions de déclenchement Lambda @ Edge pour réécrire certaines requêtes avant qu'elles ne passent à S3 et réécrire les erreurs 403/404 sur les chemins sans la barre oblique de fin, pour les rediriger.


3 Réponses :



4
votes

S3 propose uniquement des documents d'indexation automatique lorsque vous avez activé et que vous utilisez les fonctionnalités d'hébergement de site Web du compartiment, en pointant vers le point de terminaison d'hébergement de site Web du compartiment, $ {bucket} .s3-website. $ {region } .amazonaws.com plutôt que le point de terminaison REST générique du bucket, $ {bucket} .s3.amazonaws.com .

Les points de terminaison de site Web et les points de terminaison REST ont nombreuses différences , y compris celle-ci.

Le La raison pour laquelle vous voyez ces fichiers de 0 octet pour les clés d'objet se terminant par / est que vous créez des objets de dossier dans le compartiment à l'aide de la console S3 ou d'un autre utilitaire qui crée en fait les objets de 0 octet. Ils ne sont pas nécessaires, une fois que les dossiers ont des objets "dans" eux - mais ils sont le seul moyen d'afficher un dossier vide dans la console S3, qui affiche un objet nommé foo / comme un dossier nommé foo , même s'il n'y a pas d'autres objets avec un préfixe de clé foo / . Cela fait partie de l'émulation visuelle d'une hiérarchie de dossiers dans la console, même si les objets dans S3 ne sont jamais vraiment "dans" des dossiers.

Si, pour une raison quelconque, vous devez utiliser le point de terminaison REST - comme vous ne voulez pas rendre le bucket public - alors vous avez besoin de deux déclencheurs Lambda @ Edge dans CloudFront, pour émuler cette fonctionnalité assez étroitement.

Un déclencheur Origin Request peut inspecter et modifier les demandes après la vérification du cache CloudFront, avant que la demande ne soit envoyée à l'origine. Nous utilisons ceci pour rechercher un chemin se terminant par / et ajouter index.html si nous trouvons cela.

Une Réponse d'origine em> trigger peut inspecter et éventuellement modifier les réponses, avant qu'elles ne soient écrites dans le cache CloudFront. Le déclencheur Origin Response peut également inspecter la demande d'origine qui a précédé la demande qui a généré la réponse. Nous utilisons ceci pour vérifier si la réponse est une erreur. Si tel est le cas et que la demande d'origine ne semble pas concerner un document d'index ou un fichier (en particulier, après la dernière barre oblique du chemin, un "fichier" comporte au moins un caractère, suivi de un point, suivi d'au moins un caractère supplémentaire - et si c'est le cas, c'est probablement un "fichier"). Si ce n'est ni l'une ni l'autre de ces choses, nous redirigeons vers le chemin d'origine plus un / final que nous ajoutons.

Les déclencheurs Origin Request et Origin Response se déclenchent uniquement en cas d'échec du cache. Lorsqu'il y a un hit de cache, aucun des déclencheurs ne se déclenche, car ils se trouvent du côté d'origine de CloudFront - l'arrière du cache. Les requêtes qui peuvent être servies à partir du cache sont servies à partir du cache, donc les déclencheurs ne sont pas appelés.

Ce qui suit est une fonction Lambda @ Edge écrite dans Node.js 8.10. Cette fonction Lambda modifie son comportement afin qu'elle se comporte comme une demande d'origine ou une réponse d'origine, en fonction du contexte. Après avoir publié une version dans Lambda, associez l'ARN de cette version aux paramètres CloudFront Cache Behavior en tant que à la fois une demande d'origine et un déclencheur de réponse d'origine.

'use strict';

// combination origin-request, origin-response trigger to emulate the S3
// website hosting index document functionality, while using the REST
// endpoint for the bucket

// https://stackoverflow.com/a/54263794/1695906

const INDEX_DOCUMENT = 'index.html'; // do not prepend a slash to this value

const HTTP_REDIRECT_CODE = '302'; // or use 301 or another code if desired
const HTTP_REDIRECT_MESSAGE = 'Found'; 

exports.handler = (event, context, callback) => {
    const cf = event.Records[0].cf;

    if(cf.config.eventType === 'origin-request')
    {
        // if path ends with '/' then append INDEX_DOCUMENT before sending to S3
        if(cf.request.uri.endsWith('/'))
        {
            cf.request.uri = cf.request.uri + INDEX_DOCUMENT;
        }
        // return control to CloudFront, to send request to S3, whether or not
        // we modified it; if we did, the modified URI will be requested.
        return callback(null, cf.request);
    }
    else if(cf.config.eventType === 'origin-response')
    {
        // is the response 403 or 404?  If not, we will return it unchanged.
        if(cf.response.status.match(/^40[34]$/))
        {
            // it's an error.

            // we're handling a response, but Lambda@Edge can still see the attributes of the request that generated this response; so, we
            // check whether this is a page that should be redirected with a trailing slash appended.  If it doesn't look like an index
            // document request, already, and it doesn't end in a slash, and doesn't look like a filename with an extension... we'll try that.

            // This is essentially what the S3 web site endpoint does if you hit a nonexistent key, so that the browser requests
            // the index with the correct relative path, except that S3 checks whether it will actually work.  We are using heuristics,
            // rather than checking the bucket, but checking is an alternative.

            if(!cf.request.uri.endsWith('/' + INDEX_DOCUMENT) && // not a failed request for an index document
               !cf.request.uri.endsWith('/') && // unlikely, unless this code is modified to pass other things through on the request side
               !cf.request.uri.match(/[^\/]+\.[^\/]+$/)) // doesn't look like a filename  with an extension
            {
                // add the original error to the response headers, for reference/troubleshooting
                cf.response.headers['x-redirect-reason'] = [{ key: 'X-Redirect-Reason', value: cf.response.status + ' ' + cf.response.statusDescription }];
                // set the redirect code
                cf.response.status = HTTP_REDIRECT_CODE;
                cf.response.statusDescription = HTTP_REDIRECT_MESSAGE;
                // set the Location header with the modified URI
                // just append the '/', not the "index.html" -- the next request will trigger
                // this function again, and it will be added without appearing in the
                // browser's address bar.
                cf.response.headers['location'] = [{ key: 'Location', value: cf.request.uri + '/' }];
                // not strictly necessary, since browsers don't display it, but remove the response body with the S3 error XML in it
                cf.response.body = '';
            }
        }

        // return control to CloudFront, with either the original response, or
        // the modified response, if we modified it.

        return callback(null, cf.response);

    }
    else // this is not intended as a viewer-side trigger.  Throw an exception, visible only in the Lambda CloudWatch logs and a 502 to the browser.
    {
        return callback(`Lambda function is incorrectly configured; triggered on '${cf.config.eventType}' but expected 'origin-request' or 'origin-response'`);
    }

};

p >


2 commentaires

C'est en profondeur, merci beaucoup !!! Je crains de rendre le seau public, mais je suppose que je n'ai pas à l'être. J'ai également hâte que CloudFront devienne un CDN Web. J'ai d'autres besoins comme un routage plus avancé (example.com/users/username, où le nom d'utilisateur est passé en tant que variable ... et cetera). Je pense que je vais essayer votre fonction Lambda @ Edge, merci beaucoup !!!


Cela marche. J'ai également testé avec une distribution CloudFront qui utilise une fonction Lambda pour l'authentification et cela fonctionne. Avant fixation, pour un sous-dossier de site Web / test-folder / . Microsoft Edge crée des fichiers Téléchargements vides nommés dossier-test * et Chrome crée des fichiers vides nommés téléchargement * . Cette réponse a résolu ce problème.



4
votes

Les réponses données sont fausses. Cloudfront a sa propre configuration pour que www.yourdomain.com/ serve un document. Il s'appelle «objet racine par défaut» et sa configuration se trouve sous l'onglet «général» de votre distribution cloudfront. Voici les étapes complètes pour obtenir un domaine personnalisé compatible SSL / https + cloudfront + s3.

  1. Créez un tout nouveau compartiment S3 avec des autorisations par défaut (fermées) ou supprimez tous les accès publics du compartiment cible.
  2. Désactivez l'hébergement de site Web statique. Vous n'en avez pas besoin.
  3. Si vous ne l'avez pas déjà fait, récupérez votre certificat SSL dans Amazon afin de pouvoir le joindre à la distribution cloudfront qui pointera vers votre compartiment S3.
  4. Créez une distribution cloudfront pointant vers le compartiment S3 cible, à l'aide du certificat.
  5. Pour la configuration de l'origine, utilisez le formulaire www.votredomaine.com.s3.amazonaws.com pour l'origine, PAS l'URL d'hébergement du site Web statique (qui devrait de toute façon être désactivée).
  6. Laissez la configuration cloudfront modifier automatiquement l'accès au compartiment S3 ("restreindre l'accès au compartiment"). Vous souhaitez que l'accès au compartiment soit limité à cette distribution cloudfront UNIQUEMENT (via une identité spécifique). Personne ne devrait toucher directement votre compartiment S3, d'autant plus qu'il peut servir via http (pas de "s").
  7. Sous l'onglet "général" de cloudfront (ou pendant l'installation), définissez votre objet racine par défaut sur "index.html" ou autre. Sinon, les demandes adressées à https://www.yourdomain.com/ afficheront l'autorisation refusée.

2 commentaires

C'est une meilleure solution car elle évite de donner un accès public à un compartiment S3.


L'onglet Général n'existe plus. Recherchez dans la page "Objet racine par défaut"