One place for hosting & domains

      créer

      Comment créer des éléments par glisser-déposer avec Vanilla JavaScript et HTML


      Introduction

      Le glisser-déposer est une interaction utilisateur courante que vous pouvez trouver dans de nombreuses interfaces graphiques.

      Il existe des bibliothèques JavaScript préexistantes permettant d’ajouter une fonction de glisser-déposer à votre application. Toutefois, il peut arriver qu’une bibliothèque ne soit pas disponible ou qu’elle introduise une surcharge ou une dépendance dont votre projet n’a pas besoin. Dans de telles situations, la connaissance des API dont vous disposez dans les navigateurs web modernes peut vous offrir des solutions alternatives.

      L’API HTML Drag and Drop s’appuie sur le modèle d’événement de DOM pour obtenir des informations sur ce qui est glissé ou déposé et pour mettre à jour cet élément par glisser-déposer. Grâce aux gestionnaires d’événements JavaScript, vous pouvez transformer n’importe quel élément en un élément pouvant être glissé ou déposé.

      Dans ce tutoriel, nous allons construire un exemple de glisser-déposer en utilisant l’API HTML Drag and Drop avec Vanilla JavaScript pour utiliser les gestionnaires d’événements.

      Conditions préalables

      Pour suivre ce tutoriel, vous aurez besoin de :

      • Un navigateur web moderne qui supporte l’API Drag and Drop (Chrome 4+, Firefox 3.5+, Safari 3.1+, Edge 18+).

      Étape 1 – Création du projet et balisage initial

      Notre projet consistera en un conteneur avec deux types d’éléments enfant :

      • Des éléments enfant que vous pouvez faire glisser
      • Des éléments enfant dans lesquels il est possible de déposer des éléments

      Tout d’abord, ouvrez la fenêtre de votre terminal et créez un nouveau répertoire de projets :

      • mkdir drag-and-drop-example

      Ensuite, naviguez vers ce répertoire :

      Puis créez un fichier index.html dans ce répertoire :

      Ajoutez maintenant du code passe-partout pour une page web HTML :

      index.html

      <!DOCTYPE html>
      <html>
        <head>
          <title>My Drag-and-Drop Example</title>
          <link rel="stylesheet" href="https://www.digitalocean.com/community/tutorials/style.css" />
        </head>
        <body>
        </body>
      </html>
      

      Et entre les balises <body> ajoutez votre élément draggable et votre dropzone (cible de largage) :

      index.html

      <div class="example-parent">
        <div class="example-origin">
          <div
            id="draggable-1"
            class="example-draggable"
          >
            draggable
          </div>
        </div>
      
        <div
          class="example-dropzone"
        >
          dropzone
        </div>
      </div>
      

      Enregistrez et fermez le fichier. Ensuite, créez un fichier style.css :

      Puis, ajoutez des styles pour les éléments de notre fichier index.html :

      style.css

      .example-parent {
        border: 2px solid #DFA612;
        color: black;
        display: flex;
        font-family: sans-serif;
        font-weight: bold;
      }
      
      .example-origin {
        flex-basis: 100%;
        flex-grow: 1;
        padding: 10px;
      }
      
      .example-draggable {
        background-color: #4AAE9B;
        font-weight: normal;
        margin-bottom: 10px;
        margin-top: 10px;
        padding: 10px;
      }
      
      .example-dropzone {
        background-color: #6DB65B;
        flex-basis: 100%;
        flex-grow: 1;
        padding: 10px;
      }
      

      Cela permettra d'ajouter un certain formatage à l'application. Vous pouvez maintenant visualiser index.html dans le navigateur et observer que cela produit un dragable <div> et un dropzone <div>.

      Capture d'écran des div draggable et dropzone

      Ensuite, nous rendrons explicitement le premier <div> glissant en ajoutant l'attribut draggable :

      index.html

      <div class="example-parent">
        <div class="example-origin">
          <div
            id="draggable-1"
            class="example-draggable"
            draggable="true"
          >
            draggable
          </div>
        </div>
      
        <div
          class="example-dropzone"
        >
          dropzone
        </div>
      </div>
      

      Enregistrez et fermez le fichier.

      Enfin, regardez à nouveau index.html dans le navigateur. Si nous cliquons sur le draggable <div> et le faisons glisser sur l'écran, il doit y avoir une indication visuelle de son déplacement.

      La valeur par défaut de l'attribut draggable est auto. Cela signifie que la possibilité de faire glisser l'élément sera déterminée par le comportement par défaut de votre navigateur. En général, cela signifie que les sélections de texte, les images et les liens peuvent être glissés sans qu'il soit nécessaire de spécifier draggable=" true".

      Vous avez maintenant un fichier HTML avec un élément glissant. Nous passerons à l'ajout de gestionnaires onevents.

      Étape 2 - Gestion des événements par glisser-déposer avec JavaScript

      Actuellement, si nous relâchons la souris tout en faisant glisser l'élément déplaçable, il ne se passe rien. Pour déclencher une action sur les éléments du DOM par glisser-déposer, nous devons utiliser l'API Drag and Drop :

      • ondragstart : ce gestionnaire d'événement sera attaché à notre élément draggable et se déclenchera lorsqu'un événement dragstart se produira.
      • ondragover : ce gestionnaire d'événements sera attaché à notre élément dropzone et se déclenchera lorsqu'un événement dragover se produira.
      • ondrop : ce gestionnaire d'événements sera également attaché à notre élément dropzone et se déclenchera lorsqu'un événement drop se produira.

      Remarque : il y a huit gestionnaires d'événements au total : ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart et ondrop. Dans le cadre de notre exemple, nous n'aurons pas besoin de tous.

      Tout d'abord, référençons un nouveau fichier script.js dans notre index.html :

      index.html

      <body>
        ...
        <script src="https://www.digitalocean.com/community/tutorials/script.js"></script>
      </body>
      

      Ensuite, nous allons créer un nouveau fichier script.js :

      L'objet DataTransfer conservera les informations relatives à la traînée actuelle. Pour mettre à jour notre élément par glisser-déposer, nous devons accéder directement à l'objet DataTransfer. Pour ce faire, nous pouvons sélectionner la propriété dataTransfer de l'élément DOM DragEvent.

      Remarque : l'objet DataTransfer peut techniquement suivre les informations de plusieurs éléments glissés en même temps. Dans le cadre de notre exemple, nous nous concentrerons sur le glissement d'un élément.

      La méthode setData de l'objet dataTransfer peut être utilisée afin de définir les informations d'état de glissement pour votre élément actuellement glissé. Il faut deux paramètres :

      • une chaîne qui déclare le format du deuxième paramètre
      • les données réelles transférées

      Notre objectif est de déplacer notre élément draggable vers un nouvel élément parent. Nous devons pouvoir sélectionner notre élément draggable avec un identifiant unique. Nous pouvons définir l’identifiant de l'élément glissé avec la méthode setData pour qu'il puisse être utilisé plus tard.

      Revisitons notre fichier script.js et créons une nouvelle fonction pour utiliser setData :

      script.js

      function onDragStart(event) {
        event
          .dataTransfer
          .setData('text/plain', event.target.id);
      }
      

      Remarque : Internet Explorer 9 à 11 aurait des problèmes avec l'utilisation de "text/plain". Le format doit être 'text' pour ce navigateur.

      Pour mettre à jour le style CSS de l'élément glissé, nous pouvons accéder à ses styles en utilisant à nouveau l'événement DOM et en définissant les styles que nous voulons pour la currentTarget.

      Ajoutons-les à notre fonction et changeons la backgroundColor en yellow :

      script.js

      function onDragStart(event) {
        event
          .dataTransfer
          .setData('text/plain', event.target.id);
      
        event
          .currentTarget
          .style
          .backgroundColor="yellow";
      }
      

      Remarque : tous les styles que vous modifiez devront être à nouveau mis à jour manuellement sur drop si vous souhaitez des styles par glisser-déposer. Si vous changez quelque chose quand il commence à glisser, l'élément glissé conservera ce nouveau style à moins que vous ne le changiez à nouveau.

      Maintenant, nous avons notre fonction JavaScript pour le démarrage du glissement.

      Nous pouvons ajouter ondragstart à l'élément draggable dans index.html :

      index.html

      <div class="example-parent">
        <div class="example-origin">
          <div
            id="draggable-1"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            draggable
          </div>
        </div>
      
        <div class="example-dropzone">
          dropzone
        </div>
      </div>
      

      Consultez index.html dans votre navigateur. Si vous essayez de faire glisser votre objet maintenant, le style déclaré dans notre fonction sera appliqué :

      Gif animé représentant un élément se faisant glisser mais ne pouvant pas être déposer

      Cependant, rien ne se passera lorsque vous relâcherez votre clic.

      Le prochain gestionnaire d'événements déclenché dans cette séquence est ondragover.

      Le comportement par défaut de certains éléments DOM comme <div> dans les navigateurs n'accepte généralement pas d'être déposé. Ce comportement interceptera le comportement que nous essayons de mettre en œuvre. Pour nous assurer que nous obtenons le comportement drop souhaité, nous appliquerons preventDefault.

      Revisitons notre fichier script.js et créons une nouvelle fonction pour utiliser preventDefault. Ajoutez ce code à la fin du fichier :

      script.js

      function onDragOver(event) {
        event.preventDefault();
      }
      

      Maintenant, nous pouvons ajouter ondragover à notre élément dropzone dans index.html :

      index.html

      <div class="example-parent">
        <div class="example-origin">
          <div
            id="draggable-1"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            draggable
          </div>
        </div>
      
        <div
          class="example-dropzone"
          ondragover="onDragOver(event);"
        >
          dropzone
        </div>
      </div>
      

      À ce stade, nous n'avons toujours pas de code écrit pour gérer le dépôt réel. Le dernier gestionnaire d'événements déclenché dans cette séquence est ondrop.

      Revoyons notre fichier script.js et créons une nouvelle fonction.

      Nous pouvons référencer les données que nous avons enregistrées précédemment avec la méthode setData de l'objet dataTransfer. Nous utiliserons la méthode getData de l'objet dataTransfer. Les données que nous avons établies étaient l’id, c'est donc ce qui nous sera renvoyé :

      script.js

      function onDrop(event) {
        const id = event
          .dataTransfer
          .getData('text');
      }
      

      Sélectionnons notre élément draggable avec l’id que nous avons récupéré :

      script.js

      function onDrop(event) {
        // ...
      
        const draggableElement = document.getElementById(id);
      }
      

      Sélectionnons notre élément dropzone :

      script.js

      function onDrop(event) {
        // ...
      
        const dropzone = event.target;
      }
      

      Ajoutons notre élément draggable à la dropzone :

      script.js

      function onDrop(event) {
        // ...
      
        dropzone.appendChild(draggableElement);
      }
      

      Réinitialisons notre objet DataTransfer :

      script.js

      function onDrop(event) {
        // ...
      
        event
          .dataTransfer
          .clearData();
      }
      

      Maintenant, nous pouvons ajouter ondrop à notre élément dropzone dans index.html :

      index.html

      <div class="example-parent">
        <div class="example-origin">
          <div
            id="draggable-1"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            draggable
          </div>
        </div>
      
        <div
          class="example-dropzone"
          ondragover="onDragOver(event);"
          ondrop="onDrop(event);"
        >
          dropzone
        </div>
      </div>
      

      Une fois que cela est fait, nous avons une fonction de glisser-déposer fonctionnelle. Affichez index.html dans votre navigateur et faites glisser l'élément draggable sur la dropzone.

      Gif animé représentant un élément glissé et déposé dans une cible de largage

      Notre exemple porte sur le scénario d'un seul objet pouvant être déplacé et d'une seule cible de largage. Vous pouvez avoir plusieurs objets à faire glisser, plusieurs cibles où les déposer, et personnaliser tout cela avec tous les autres gestionnaires d'événements de l'API Drag and Drop.

      Étape 3 - Construction d'un exemple complexe avec plusieurs éléments glissants

      Voici un autre exemple de la manière dont vous pourriez utiliser cette API : une liste de tâches avec des tâches glissantes que vous pouvez déplacer d'une colonne "To-do" à une colonne "Done".

      Gif animé représentant plusieurs tâches glissées et déposées dans une colonne Done

      Pour créer votre propre liste de tâches, ajoutez à index.html d'autres éléments à faire glisser avec des ids uniques :

      index.html

      <div class="example-parent">
        <h1>To-do list</h1>
        <div class="example-origin">
          To-do
          <div
            id="draggable-1"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            thing 1
          </div>
          <div
            id="draggable-2"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            thing 2
          </div>
          <div
            id="draggable-3"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            thing 3
          </div>
          <div
            id="draggable-4"
            class="example-draggable"
            draggable="true"
            ondragstart="onDragStart(event);"
          >
            thing 4
          </div>
        </div>
      
        <div
          class="example-dropzone"
          ondragover="onDragOver(event);"
          ondrop="onDrop(event);"
        >
          Done
        </div>
      </div>
      

      Affichez index.html dans votre navigateur et faites glisser les éléments de la colonne To-do vers la colonne Done. Vous avez créé une application to-do et testé la fonctionnalité.

      Conclusion

      Dans cet article, vous avez créé une application to-do pour explorer la fonctionnalité de glisser-déposer qui est disponible pour les navigateurs web modernes.

      L'API Drag and Drop offre de multiples options pour personnaliser vos actions au-delà du simple glisser-déposer. Par exemple, vous pouvez mettre à jour le style CSS de vos éléments glissés. Vous pouvez également, au lieu de déplacer l'élément, choisir de copier votre élément déplaçable afin qu'il soit reproduit lors du dépôt.

      Gardez à l'esprit que si de nombreux navigateurs web prennent en charge cette technologie, vous ne pourrez peut-être pas vous y fier si votre public se compose d’appareils qui ne prennent pas en charge cette fonctionnalité.

      Pour en savoir plus sur tout ce que vous pouvez déposer avec l'API Drag and Drop, consultez les documents du MDN à ce sujet.



      Source link

      Comment créer une pagination personnalisée avec React


      Introduction

      Nous nous impliquons souvent dans la construction d’applications web où nous devons récupérer de grands ensembles de données à partir d’un serveur distant, d’une API ou d’une base de données. Si vous mettez en place un système de paiement, par exemple, il peut aller chercher des milliers de transactions. S’il s’agit d’une app de réseaux sociaux, elle peut récupérer de nombreux commentaires, profils ou activités d’utilisateurs. Quoi qu’il en soit, il existe plusieurs solutions pour présenter les données d’une manière qui ne submerge pas l’utilisateur final qui interagit avec l’app.

      Une méthode pour traiter de grands ensembles de données consiste à utiliser la pagination. La pagination fonctionne efficacement lorsque vous connaissez à l’avance la taille de l’ensemble de données (le nombre total d’enregistrements contenu dans l’ensemble de données). Deuxièmement, vous ne chargez que le morceau de données requis de l’ensemble des données en fonction de l’interaction de l’utilisateur final avec le contrôle de pagination. C’est la technique utilisée pour afficher les résultats de recherche dans Google Search.

      Dans ce tutoriel, vous apprendrez comment construire un composant de pagination personnalisé avec React pour la pagination de grands ensembles de données. Vous construirez une vue paginée des pays du monde – un ensemble de données dont la taille est connue.

      Voici une démo de ce que vous allez construire dans ce tutoriel :

      Capture d'écran de l'application de démo - montrant les pays du monde

      Conditions préalables

      Pour suivre ce tutoriel, vous aurez besoin de :

      Ce tutoriel a été vérifié avec Node v14.2.0, npm v6.14.4, react v16.13.1, et react-scripts v3.4.1.

      Étape 1 – Mettre en place le projet

      Lancez une nouvelle application React en utilisant la commande create-react-app. Vous pouvez nommer l’application comme vous le souhaitez, mais ce tutoriel lui donnera le nom react-pagination :

      • npx create-react-app react-pagination

      Ensuite, vous installerez les dépendances nécessaires pour votre application. Tout d’abord, utilisez la fenêtre du terminal pour accéder au répertoire du projet :

      Exécutez la commande suivante pour installer les dépendances requises :

      • npm install bootstrap@4.1.0 prop-types@15.6.1 react-flags@0.1.13 countries-api@2.0.1 node-sass@4.14.1

      Vous installerez alors bootstrap, prop-types, react-flags, countries-api et node-sass.

      Vous avez installé le bootstrap comme une dépendance de votre demande, car vous aurez besoin d’un style par défaut. Vous utiliserez également les styles du composant de pagination Bootstrap.

      Pour inclure Bootstrap dans l’application, modifiez le fichier src/index.js :

      Et ajoutez la ligne suivante avant les autres déclarations d’import :

      src/index.js

      import "bootstrap/dist/css/bootstrap.min.css";
      

      Maintenant, le style Bootstrap sera disponible dans toute votre application.

      Vous avez également installé react-flags comme une dépendance de votre application. Afin d’accéder aux icônes des drapeaux à partir de votre application, vous devez copier les images des icônes dans le répertoire public de votre application.

      Créez un répertoire img dans votre répertoire public :

      Copiez les fichiers images dans flags vers img :

      • cp -R node_modules/react-flags/vendor/flags public/img

      Ce document fournit une copie de tous les react-flag à votre application.

      Maintenant que vous avez inclus quelques dépendances, lancez l’application en exécutant la commande suivante avec npm de la pagination du répertoire du projet react-pagination :

      Maintenant que vous avez lancé l’application, le développement peut commencer. Vous remarquerez qu’un onglet du navigateur a été ouvert pour vous avec la fonctionnalité de rechargement live pour rester en phase avec l’application au fur et à mesure de son développement.

      À ce stade, la vue de l’application devrait ressembler à la capture d’écran suivante :

      Vue initiale - Bienvenue sur React Screen

      Vous êtes maintenant prêt à commencer à créer des composants.

      Étape 2 – Créer le composant CountryCard

      Dans cette étape, vous allez créer le composant CountryCard. Le composant CountryCard génère le nom, la région et le drapeau d’un pays donné.

      Tout d’abord, créons un composant dans le répertoire src :

      Ensuite, créez une nouvelle CountryCard.js dans le répertoire src/components :

      • nano src/components/CountryCard.js

      Et ajoutez-y le code suivant :

      src/components/CountryCard.js

      import React from 'react';
      import PropTypes from 'prop-types';
      import Flag from 'react-flags';
      
      const CountryCard = props => {
        const {
          cca2: code2 = '', region = null, name = {}
        } = props.country || {};
      
        return (
          <div className="col-sm-6 col-md-4 country-card">
            <div className="country-card-container border-gray rounded border mx-2 my-3 d-flex flex-row align-items-center p-0 bg-light">
              <div className="h-100 position-relative border-gray border-right px-2 bg-white rounded-left">
                <Flag country={code2} format="png" pngSize={64} basePath="./img/flags" className="d-block h-100" />
              </div>
              <div className="px-3">
                <span className="country-name text-dark d-block font-weight-bold">{ name.common }</span>
                <span className="country-region text-secondary text-uppercase">{ region }</span>
              </div>
            </div>
          </div>
        )
      }
      
      CountryCard.propTypes = {
        country: PropTypes.shape({
          cca2: PropTypes.string.isRequired,
          region: PropTypes.string.isRequired,
          name: PropTypes.shape({
            common: PropTypes.string.isRequired
          }).isRequired
        }).isRequired
      };
      
      export default CountryCard;
      

      Le composant CountryCard nécessite un prop country qui contient les données sur le pays à afficher. Comme on l’a vu dans le module propTypes pour le composant CountryCard, l’objet prop country doit contenir les données suivantes :

      • cca2 – un code de pays à deux chiffres
      • region – la région du pays (par exemple, « Africa »)
      • name.common – le nom commun du pays (par exemple, « Nigeria »)

      Voici un exemple d’objet country :

      {
        cca2: "NG",
        region: "Africa",
        name: {
          common: "Nigeria"
        }
      }
      

      Notez également comment vous rendez le drapeau du pays en utilisant le paquet react-flags. Vous pouvez consulter la documentation react-flags pour en savoir plus sur les props nécessaires et sur la façon d’utiliser le paquet.

      Vous avez maintenant un composant CountryCard complété. Enfin, vous utiliserez CountryCard plusieurs fois pour afficher dans votre application différents drapeaux et différentes informations sur le pays.

      Dans cette étape, vous créerez le composant Pagination. Le composant Pagination contient la logique de construction, de rendu et de commutation des pages sur le contrôle de pagination.

      Ensuite, créez une nouvelle Pagination.js dans le répertoire src/components :

      • nano src/components/Pagination.js

      Et ajoutez-y le code suivant :

      src/components/Pagination.js

      import React, { Component, Fragment } from 'react';
      import PropTypes from 'prop-types';
      
      class Pagination extends Component {
        constructor(props) {
          super(props);
          const { totalRecords = null, pageLimit = 30, pageNeighbours = 0 } = props;
      
          this.pageLimit = typeof pageLimit === 'number' ? pageLimit : 30;
          this.totalRecords = typeof totalRecords === 'number' ? totalRecords : 0;
      
          // pageNeighbours can be: 0, 1 or 2
          this.pageNeighbours = typeof pageNeighbours === 'number'
            ? Math.max(0, Math.min(pageNeighbours, 2))
            : 0;
      
          this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);
      
          this.state = { currentPage: 1 };
        }
      }
      
      Pagination.propTypes = {
        totalRecords: PropTypes.number.isRequired,
        pageLimit: PropTypes.number,
        pageNeighbours: PropTypes.number,
        onPageChanged: PropTypes.func
      };
      
      export default Pagination;
      

      Le volet Pagination peut prendre quatre props spéciaux, comme indiqué dans l’objet propTypes.

      • onPageChanged est une fonction appelée avec les données de l’état de pagination actuel uniquement lorsque la page en cours change.
      • totalRecords indique le nombre total de documents à paginer. C’est un obligatoire.
      • pageLimit indique le nombre d’enregistrements à afficher par page. Si elle n’est pas spécifiée, la valeur par défaut est 30 tel que défini dans la constructor().
      • pageNeighbours indique le nombre de numéros de page supplémentaires à afficher de chaque côté de la page en cours. La valeur minimale est 0 et la valeur maximale est 2. Si elle n’est pas spécifiée, la valeur par défaut est 0, comme définie dans la fonction constructor().

      L’image suivante illustre l’effet des différentes valeurs du prop pageNeighbours :

      Illustration de la page Neighbours

      Dans la fonction constructor(), vous calculez le nombre total de pages comme suit :

      this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);
      

      Vous remarquerez que vous utilisez la fonctionMath.ceil() ici pour vous assurer que vous obtenez une valeur entière pour le nombre total de pages. Cela garantit également que les documents excédentaires soient saisis à la dernière page, en particulier dans les cas où le nombre de documents excédentaires est inférieur au nombre de documents à afficher par page.

      Enfin, vous avez initialisé l’état avec la propriété currentPage réglée sur 1. Vous avez besoin de cette propriété d’état pour garder une trace de la page actuellement active en interne.

      Ensuite, vous créerez la méthode pour générer les numéros de page.

      Après les importations mais avant la classe Pagination, ajoutez les constantes et la fonction de plage suivantes :

      src/components/Pagination.js

      // ...
      
      const LEFT_PAGE = 'LEFT';
      const RIGHT_PAGE = 'RIGHT';
      
      /**
       * Helper method for creating a range of numbers
       * range(1, 5) => [1, 2, 3, 4, 5]
       */
      const range = (from, to, step = 1) => {
        let i = from;
        const range = [];
      
        while (i <= to) {
          range.push(i);
          i += step;
        }
      
        return range;
      }
      

      Dans la classe Pagination, après la fonction constructor, ajoutez la méthode fetchPageNumbers qui suit :

      src/components/Pagination.js

      class Pagination extends Component {
        // ...
      
        /**
         * Let's say we have 10 pages and we set pageNeighbours to 2
         * Given that the current page is 6
         * The pagination control will look like the following:
         *
         * (1) < {4 5} [6] {7 8} > (10)
         *
         * (x) => terminal pages: first and last page(always visible)
         * [x] => represents current page
         * {...x} => represents page neighbours
         */
        fetchPageNumbers = () => {
          const totalPages = this.totalPages;
          const currentPage = this.state.currentPage;
          const pageNeighbours = this.pageNeighbours;
      
          /**
           * totalNumbers: the total page numbers to show on the control
           * totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
           */
          const totalNumbers = (this.pageNeighbours * 2) + 3;
          const totalBlocks = totalNumbers + 2;
      
          if (totalPages > totalBlocks) {
            const startPage = Math.max(2, currentPage - pageNeighbours);
            const endPage = Math.min(totalPages - 1, currentPage + pageNeighbours);
            let pages = range(startPage, endPage);
      
            /**
             * hasLeftSpill: has hidden pages to the left
             * hasRightSpill: has hidden pages to the right
             * spillOffset: number of hidden pages either to the left or to the right
             */
            const hasLeftSpill = startPage > 2;
            const hasRightSpill = (totalPages - endPage) > 1;
            const spillOffset = totalNumbers - (pages.length + 1);
      
            switch (true) {
              // handle: (1) < {5 6} [7] {8 9} (10)
              case (hasLeftSpill && !hasRightSpill): {
                const extraPages = range(startPage - spillOffset, startPage - 1);
                pages = [LEFT_PAGE, ...extraPages, ...pages];
                break;
              }
      
              // handle: (1) {2 3} [4] {5 6} > (10)
              case (!hasLeftSpill && hasRightSpill): {
                const extraPages = range(endPage + 1, endPage + spillOffset);
                pages = [...pages, ...extraPages, RIGHT_PAGE];
                break;
              }
      
              // handle: (1) < {4 5} [6] {7 8} > (10)
              case (hasLeftSpill && hasRightSpill):
              default: {
                pages = [LEFT_PAGE, ...pages, RIGHT_PAGE];
                break;
              }
            }
      
            return [1, ...pages, totalPages];
          }
      
          return range(1, totalPages);
        }
      }
      

      Ici, vous définissez d’abord deux constantes : LEFT_PAGE et RIGHT_PAGE. Ces constantes seront utilisées pour indiquer les points où vous avez des contrôles de page pour vous déplacer respectivement à gauche et à droite.

      Vous avez également défini une aide avec la fonctionrange() qui peut vous aider à générer des séries de chiffres.

      Note : Si vous utilisez une bibliothèque d’utilité comme Lodashdans votre projet, vous pouvez alors utiliser la fonction _.range() fournie par Lodash à la place. L’extrait de code suivant montre la différence entre la fonction range() que vous venez de définir et celle de Lodash :

      range(1, 5); // returns [1, 2, 3, 4, 5]
      _.range(1, 5); // returns [1, 2, 3, 4]
      

      Ensuite, vous avez défini la méthode fetchPageNumbers() dans la classe Pagination. Cette méthode gère la logique de base pour générer les numéros de page à afficher sur le contrôle de pagination. Vous voulez que la première page et la dernière page soient toujours visibles.

      Tout d’abord, vous avez défini quelques variables. totalNumbers représente le nombre total de pages qui seront affichées sur le contrôle. totalBlocks représente le nombre total de pages à afficher, plus deux blocs supplémentaires pour les indicateurs de page gauche et droite.

      Si le nombre totalPages n’est pas supérieur à totalBlocks, vous renvoyez une série de chiffres allant de 1 à totalPages. Sinon, vous renvoyez le tableau des numéros de page, avec LEFT_PAGE et RIGHT_PAGE aux endroits où vous avez des pages qui débordent respectivement à gauche et à droite.

      Toutefois, notez que votre contrôle de pagination garantit que la première page et la dernière page sont toujours visibles. Les contrôles des pages gauche et droite apparaissent vers l’intérieur.

      Maintenant, vous allez ajouter la fonction render() pour vous permettre de contrôler la pagination.

      Dans la classe Pagination, après la méthode constructor et fetchPageNumbers, ajoutez la méthode render suivante :

      src/components/Pagination.js

      class Pagination extends Component {
        // ...
      
        render() {
          if (!this.totalRecords || this.totalPages === 1) return null;
      
          const { currentPage } = this.state;
          const pages = this.fetchPageNumbers();
      
          return (
            <Fragment>
              <nav aria-label="Countries Pagination">
                <ul className="pagination">
                  { pages.map((page, index) => {
      
                    if (page === LEFT_PAGE) return (
                      <li key={index} className="page-item">
                        <a className="page-link" href="https://www.digitalocean.com/community/tutorials/#" aria-label="Previous" onClick={this.handleMoveLeft}>
                          <span aria-hidden="true">&laquo;</span>
                          <span className="sr-only">Previous</span>
                        </a>
                      </li>
                    );
      
                    if (page === RIGHT_PAGE) return (
                      <li key={index} className="page-item">
                        <a className="page-link" href="https://www.digitalocean.com/community/tutorials/#" aria-label="Next" onClick={this.handleMoveRight}>
                          <span aria-hidden="true">&raquo;</span>
                          <span className="sr-only">Next</span>
                        </a>
                      </li>
                    );
      
                    return (
                      <li key={index} className={`page-item${ currentPage === page ? ' active' : ''}`}>
                        <a className="page-link" href="https://www.digitalocean.com/community/tutorials/#" onClick={ this.handleClick(page) }>{ page }</a>
                      </li>
                    );
      
                  }) }
      
                </ul>
              </nav>
            </Fragment>
          );
        }
      }
      

      Ici, vous générez le tableau des numéros de page en appelant la fonction fetchPageNumbers() que vous avez créée précédemment. Vous générez ensuite chaque numéro de page en utilisant Array.prototype.map(). Notez que vous enregistrez des gestionnaires d’événements de clic sur chaque numéro de page généré pour gérer les clics.

      Notez également que le contrôle de la pagination ne sera pas effectué si le proptotalRecords n’a pas été correctement transmis au composant Pagination ou dans les cas où il n’y a qu’une page 1.

      Enfin, vous définirez les méthodes de gestion des événements.

      Dans la classe Pagination, après la méthode con fetchPageNumbers et la méthode render, ajoutez ce qui suit :

      src/components/Pagination.js

      class Pagination extends Component {
        // ...
      
        componentDidMount() {
          this.gotoPage(1);
        }
      
        gotoPage = page => {
          const { onPageChanged = f => f } = this.props;
          const currentPage = Math.max(0, Math.min(page, this.totalPages));
          const paginationData = {
            currentPage,
            totalPages: this.totalPages,
            pageLimit: this.pageLimit,
            totalRecords: this.totalRecords
          };
      
          this.setState({ currentPage }, () => onPageChanged(paginationData));
        }
      
        handleClick = page => evt => {
          evt.preventDefault();
          this.gotoPage(page);
        }
      
        handleMoveLeft = evt => {
          evt.preventDefault();
          this.gotoPage(this.state.currentPage - (this.pageNeighbours * 2) - 1);
        }
      
        handleMoveRight = evt => {
          evt.preventDefault();
          this.gotoPage(this.state.currentPage + (this.pageNeighbours * 2) + 1);
        }
      }
      

      Vous définissez la méthode gotoPage() qui modifie l’état et met currentPage à la page spécifiée. Elle garantit que l’argument de la page a une valeur minimale de 1 et une valeur maximale du nombre total de pages. Il appelle enfin la fonction onPageChanged() qui a été transmise comme prop, avec des données indiquant le nouvel état de pagination.

      Lorsque le composant est monté, vous passez à la première page en appelant this.gotoPage(1) comme indiqué dans la méthode de cycle de vie componentDidMount().

      Remarquez comment vous utilisez (this.pageNeighbours * 2) dans handleMoveLeft() et handleMoveRight() pour faire glisser les numéros de page vers la gauche et vers la droite, respectivement, en fonction du numéro de page en cours.

      Voici une démonstration de l’interaction du mouvement de gauche à droite.

      Mouvement gauche-droite de l'interaction

      Vous avez maintenant terminé le composant Pagination. Les utilisateurs pourront interagir avec les commandes de navigation de ce composant pour afficher différentes pages de drapeaux.

      Étape 4 – Création du composant App

      Maintenant que vous avez un composant CountryCard et Pagination, vous pouvez les utiliser dans votre composant App.

      Modifiez le fichier App.js dans le répertoire src :

      Remplacez le contenu de App.js par les lignes de code suivantes :

      src/App.js

      import React, { Component } from 'react';
      import Countries from 'countries-api';
      import './App.css';
      import Pagination from './components/Pagination';
      import CountryCard from './components/CountryCard';
      
      class App extends Component {
        state = { allCountries: [], currentCountries: [], currentPage: null, totalPages: null }
      
        componentDidMount() {
          const { data: allCountries = [] } = Countries.findAll();
          this.setState({ allCountries });
        }
      
        onPageChanged = data => {
          const { allCountries } = this.state;
          const { currentPage, totalPages, pageLimit } = data;
          const offset = (currentPage - 1) * pageLimit;
          const currentCountries = allCountries.slice(offset, offset + pageLimit);
      
          this.setState({ currentPage, currentCountries, totalPages });
        }
      }
      
      export default App;
      

      Ici, vous initialisez l’état du composant App avec les attributs suivants :

      • allCountries – Voici un tableau de tous les pays qui figurent dans votre app. Initialisé vers un tableau vide ([]).
      • currentCountries – Il s’agit d’un tableau de tous les pays qui doivent être affichés sur la page actuellement active. Initialisé vers un tableau vide ([]).
      • currentPage – Le numéro de page de la page actuellement active. Initialisé vers la valeur null.
      • totalPages – Le nombre total de pages pour l’ensemble des fiches pays. Initialisé vers la valeur null.

      Ensuite, dans la méthode du cycle de vie de componentDidMount(), vous récupérez tous les pays du monde en utilisant le paquet countries-api en invoquant Countries.findAll(). Vous mettez ensuite à jour l’état de l’application, en définissant allCountries pour contenir tous les pays du monde. Vous pouvez voir la documentation countries-apipour en savoir plus sur le paquet.

      Enfin, vous avez défini la méthode onPageChanged() qui sera appelée chaque fois que vous naviguerez vers une nouvelle page à partir du contrôle de pagination. Cette méthode sera transmise à la prop onPageChanged du composant Pagination.

      Il y a deux lignes auxquelles il convient de prêter attention dans cette méthode. La première est cette ligne :

      const offset = (currentPage - 1) * pageLimit;
      

      La valeur offset indique l’index de départ pour récupérer les enregistrements de la page en cours. En utilisant (currentPage - 1), on s’assure que la valeur offset est basée sur zéro. Disons, par exemple, que vous affichez 25 enregistrements par page, et que vous êtes en train de consulter la page 5. La valeur offset sera alors de ((5 - 1) * 25 = 100).

      Par exemple, si vous récupérez des enregistrements sur demande à partir d’une base de données, voici un exemple de requête SQL pour vous montrer comment utiliser la valeur offset :

      SELECT * FROM `countries` LIMIT 100, 25
      

      Comme vous ne récupérez pas les enregistrements d’une base de données ou d’une source externe, vous avez besoin d’un moyen d’extraire le bloc d’enregistrements requis pour la page en cours.

      La deuxième est cette ligne :

      const currentCountries = allCountries.slice(offset, offset + pageLimit);
      

      Ici, vous utilisez la méthode Array.prototype.slice() pour extraire le bloc d’enregistrements requis de allCountries en passant la valeur offset comme indice de départ de la tranche et (offset + pageLimit) comme indice avant lequel la tranche doit se terminer.

      Note : Dans ce tutoriel, vous n’avez pas récupéré d’enregistrements provenant d’une source externe. Dans une véritable application, vous irez probablement chercher des enregistrements dans une base de données ou une API. La logique de récupération des enregistrements peut être consultée dans la méthodeonPageChanged() du composant App.

      Supposons que vous ayez un point final API fictif /api/countries?page={current_page}&limit={page_limit}. L’extrait suivant montre comment vous pouvez récupérer des pays à la demande à partir de l’API en utilisant le paquet HTTP [axios][“axios] :

      onPageChanged = data => {
        const { currentPage, totalPages, pageLimit } = data;
      
        axios.get(`/api/countries?page=${currentPage}&limit=${pageLimit}`)
          .then(response => {
            const currentCountries = response.data.countries;
            this.setState({ currentPage, currentCountries, totalPages });
          });
      }
      

      Maintenant, vous pouvez achever le composantApp en ajoutant la méthode render().

      Dans la classe App, mais après componentDidMount et onPageChanged, ajoutez la méthode render suivante :

      src/App.js

      class App extends Component {
        // ... other methods here ...
      
        render() {
          const { allCountries, currentCountries, currentPage, totalPages } = this.state;
          const totalCountries = allCountries.length;
      
          if (totalCountries === 0) return null;
      
          const headerClass = ['text-dark py-2 pr-4 m-0', currentPage ? 'border-gray border-right' : ''].join(' ').trim();
      
          return (
            <div className="container mb-5">
              <div className="row d-flex flex-row py-5">
                <div className="w-100 px-4 py-5 d-flex flex-row flex-wrap align-items-center justify-content-between">
                  <div className="d-flex flex-row align-items-center">
                    <h2 className={headerClass}>
                      <strong className="text-secondary">{totalCountries}</strong> Countries
                    </h2>
                    { currentPage && (
                      <span className="current-page d-inline-block h-100 pl-4 text-secondary">
                        Page <span className="font-weight-bold">{ currentPage }</span> / <span className="font-weight-bold">{ totalPages }</span>
                      </span>
                    ) }
                  </div>
                  <div className="d-flex flex-row py-4 align-items-center">
                    <Pagination totalRecords={totalCountries} pageLimit={18} pageNeighbours={1} onPageChanged={this.onPageChanged} />
                  </div>
                </div>
                { currentCountries.map(country => <CountryCard key={country.cca3} country={country} />) }
              </div>
            </div>
          );
        }
      }
      

      Dans la méthode render(), vous générez le nombre total de pays, la page en cours, le nombre total de pages, le contrôle <Pagination>, puis la <CountryCard> pour chaque pays de la page en cours.

      Vous remarquerez que vous avez passé la méthode onPageChanged() que vous avez définie précédemment au prop onPageChanged du contrôle de <Pagination>. Ceci est très important pour la saisie des changements de page à partir du composant Pagination. Vous affichez également 18 pays par page.

      À ce stade, l’application ressemblera à la capture d’écran suivante :

      Capture d'écran de l'application avec 248 pays listés et les numéros de page indiqués en haut pour parcourir chaque page

      Vous avez maintenant une App qui affiche plusieurs composants CountryCard et uncomposant Pagination qui décompose le contenu en pages séparées. Ensuite, vous étudierez le style de votre application.

      Étape 5 – Ajout de styles personnalisés

      Vous avez peut-être remarqué que vous avez ajouté des classes personnalisées aux composants que vous avez créés précédemment. Définissons quelques règles de style pour ces classes dans le fichier src/App.scss.

      Le fichierApp.scss ressemblera à l’extrait suivant :

      src/App.scss

      /* Declare some variables */
      $base-color: #ced4da;
      $light-background: lighten(desaturate($base-color, 50%), 12.5%);
      
      .current-page {
        font-size: 1.5rem;
        vertical-align: middle;
      }
      
      .country-card-container {
        height: 60px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
      }
      
      .country-name {
        font-size: 0.9rem;
      }
      
      .country-region {
        font-size: 0.7rem;
      }
      
      .current-page,
      .country-name,
      .country-region {
        line-height: 1;
      }
      
      // Override some Bootstrap pagination styles
      ul.pagination {
        margin-top: 0;
        margin-bottom: 0;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
      
        li.page-item.active {
          a.page-link {
            color: saturate(darken($base-color, 50%), 5%) !important;
            background-color: saturate(lighten($base-color, 7.5%), 2.5%) !important;
            border-color: $base-color !important;
          }
        }
      
        a.page-link {
          padding: 0.75rem 1rem;
          min-width: 3.5rem;
          text-align: center;
          box-shadow: none !important;
          border-color: $base-color !important;
          color: saturate(darken($base-color, 30%), 10%);
          font-weight: 900;
          font-size: 1rem;
      
          &:hover {
            background-color: $light-background;
          }
        }
      }
      

      Modifiez votre fichierApp.jspour référencer App.scss au lieu de App.css.

      Remarque : Pour plus d’informations à ce sujet, voir la documentation de l’application Create React.

      src/App.js

      import React, { Component } from 'react';
      import Countries from 'countries-api';
      import './App.scss';
      import Pagination from './components/Pagination';
      import CountryCard from './components/CountryCard';
      

      Après avoir ajouté les styles, l’application ressemblera maintenant à la capture d’écran suivante :

      Capture d'écran de l'app, page 1 sur 14, avec les styles

      Vous avez maintenant une application complète avec un style personnalisé supplémentaire. Vous pouvez utiliser des styles personnalisés pour modifier et améliorer les styles par défaut fournis par des bibliothèques comme Bootstrap.

      Conclusion

      Dans ce tutoriel, vous avez créé un widget de pagination personnalisé dans votre application React. Bien que vous n’ayez pas fait d’appel à une API ou interagi avec une base de données dans ce tutoriel, votre application peut exiger de telles interactions. Vous n’êtes en aucun cas limité à l’approche utilisée dans ce tutoriel – vous pouvez l’étendre comme vous le souhaitez pour répondre aux exigences de votre application.

      Pour obtenir le code source complet de ce tutoriel, consultez le dépôt build-react-pagination-demo sur GitHub. Vous pouvez également obtenir une démo live de ce tutoriel sur Code Sandbox.

      Si vous souhaitez en savoir plus sur React, consultez notre série Comment coder dans React.js ou consultez notre page thématique React pour des exercices et des projets de programmation.



      Source link

      Comment créer un certificat SSL auto-signé pour Apache dans Ubuntu 20.04


      Introduction

      TLS, ou “transport layer security” – et son prédécesseur SSL – sont des protocoles utilisés pour envelopper le trafic normal dans une enveloppe protégée et cryptée. Grâce à cette technologie, les serveurs peuvent envoyer en toute sécurité des informations à leurs clients sans que leurs messages soient interceptés ou lus par une partie extérieure.

      Dans ce guide, nous vous montrerons comment créer et utiliser un certificat SSL auto-signé avec le serveur web Apache sur Ubuntu 20.04.

      Note : un certificat auto-signé cryptera la communication entre votre serveur et les clients éventuels. Cependant, comme il n’est signé par aucune des autorités de certification de confiance incluses avec les navigateurs web et les systèmes d’exploitation, les utilisateurs ne peuvent pas utiliser le certificat pour valider automatiquement l’identité de votre serveur. Par conséquent, vos utilisateurs verront une erreur de sécurité lorsqu’ils visiteront votre site.

      En raison de cette limitation, les certificats auto-signés ne sont pas appropriés pour un environnement de production destiné au public. Ils sont généralement utilisés pour les tests ou pour sécuriser des services non critiques utilisés par un seul utilisateur ou un petit groupe d’utilisateurs qui peuvent établir la confiance dans la validité du certificat par d’autres canaux de communication.

      Pour une solution de certificat plus adaptée à la production, consultez Let’s Encrypt, une autorité de certification gratuite. Vous pouvez apprendre comment télécharger et configurer un certificat Let’s Encrypt dans notre tutoriel Comment sécuriser Apache avec Let’s Encrypt sur Ubuntu 20.04.

      Conditions préalables

      Avant de commencer ce tutoriel, vous aurez besoin des éléments suivants :

      • Un accès à un serveur Ubuntu 20.04 avec un utilisateur non root sudo. Notre guide de configuration initiale du serveur avec Ubuntu 20.04 peut vous montrer comment créer ce compte.
      • Vous devrez également avoir installé Apache. Vous pouvez installer Apache en utilisant apt. Tout d’abord, mettez à jour l’index local des paquets afin de refléter les derniers changements en amont :

      Ensuite, installez le paquet apache2 :

      Enfin, si vous avez installé un pare-feu ufw, ouvrez les ports http et https :

      • sudo ufw allow "Apache Full"

      Une fois ces étapes terminées, assurez-vous que vous êtes connecté en tant que non- root user et poursuivez le tutoriel.

      Étape 1 — Activation de mod_ssl

      Pour pouvoir utiliser un certificat SSL quel qu’il soit, nous devons d’abord activer mod_ssl, un module Apache qui prend en charge le cryptage SSL.

      Activez mod_ssl à l’aide de la commande a2enmod :

      Redémarrez Apache pour activer le module :

      • sudo systemctl restart apache2

      Le module mod_ssl est maintenant activé et prêt à l’emploi.

      Étape 2 – Création du certificat SSL

      Maintenant qu’Apache est prêt à utiliser le cryptage, nous pouvons passer à la génération d’un nouveau certificat SSL. Le certificat stockera quelques informations de base sur votre site, et sera accompagné d’un fichier clé qui permet au serveur de traiter les données cryptées en toute sécurité.

      Nous pouvons créer les fichiers de clés et de certificats SSL avec la commande openssl :

      • sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt

      Après avoir entré la commande, vous serez amené à une invite où vous pourrez entrer des informations sur votre site web. Avant d’en parler, voyons ce qui se passe dans la commande que nous donnons :

      • openssl : c’est l’outil de ligne de commande utilisé pour la création et la gestion des certificats, clés et autres fichiers OpenSSL.
      • req -x509 : cela spécifie que nous voulons utiliser la gestion des demandes de signature de certificats (CSR) X.509. X.509 est une norme d’infrastructure de clé publique à laquelle SSL et TLS adhèrent pour la gestion des clés et des certificats.
      • -nodes : cela indique à OpenSSL de ne pas utiliser l’option de sécurisation de notre certificat par une phrase de passe. Nous avons besoin qu’Apache soit capable de lire le fichier, sans intervention de l’utilisateur, au démarrage du serveur. Une phrase de passe empêcherait que cela se produise, puisque nous devrions la saisir après chaque redémarrage.
      • -days 365 : cette option fixe la durée pendant laquelle le certificat sera considéré comme valide. Ici, nous l’avons fixée pour un an. De nombreux navigateurs modernes refusent les certificats dont la durée de validité dépasse un an.
      • -newkey rsa:2048 : cette option précise que nous voulons générer un nouveau certificat et une nouvelle clé en même temps. Nous n’avons pas créé la clé nécessaire pour signer le certificat lors d’une étape précédente, nous devons donc la créer en même temps que le certificat. La partie rsa:2048 lui demande de fabriquer une clé RSA de 2048 bits.
      • -keyout : cette ligne indique à OpenSSL où placer le fichier de clé privée généré que nous créons.
      • -out : cela indique à OpenSSL où placer le certificat que nous créons.

      Remplissez les invites de manière appropriée. La ligne la plus importante est celle qui demande le Common Name (nom commun). Vous devez entrer soit le nom d’hôte que vous utiliserez pour accéder au serveur, soit l’adresse IP publique du serveur. Il est important que ce champ corresponde à ce que vous allez mettre dans la barre d’adresse de votre navigateur pour accéder au site, car une mauvaise correspondance entraînera davantage d’erreurs de sécurité.

      La liste complète des invites ressemblera à ceci :

      Country Name (2 letter code) [XX]:US
      State or Province Name (full name) []:Example
      Locality Name (eg, city) [Default City]:Example 
      Organization Name (eg, company) [Default Company Ltd]:Example Inc
      Organizational Unit Name (eg, section) []:Example Dept
      Common Name (eg, your name or your server's hostname) []:your_domain_or_ip
      Email Address []:webmaster@example.com
      

      Les deux fichiers que vous avez créés seront placés dans les sous-répertoires appropriés sous /etc/ssl.

      Ensuite, nous mettrons à jour notre configuration Apache pour utiliser le nouveau certificat et la nouvelle clé.

      Étape 3 – Configuration d’Apache pour utiliser SSL

      Maintenant que nous disposons de notre certificat et de notre clé auto-signés, nous devons mettre à jour notre configuration Apache pour pouvoir les utiliser. Sur Ubuntu, vous pouvez placer de nouveaux fichiers de configuration Apache (ils doivent se terminer par .conf) dans /etc/apache2/sites-available/ et ils seront chargés la prochaine fois que le processus Apache sera rechargé ou redémarré.

      Pour ce tutoriel, nous allons créer un nouveau fichier de configuration minimale. (Si vous avez déjà configuré Apache <Virtualhost> et que vous devez juste y ajouter SSL, vous devrez probablement copier les lignes de configuration qui commencent par SSL, et changer le port du VirtualHost de 80 à 443. Nous nous occuperons du port 80 dans la prochaine étape).

      Ouvrez un nouveau fichier dans le répertoire /etc/apache2/sites-available :

      • sudo nano /etc/apache2/sites-available/your_domain_or_ip.conf

      Collez-y la configuration minimale suivante de VirtualHost :

      /etc/apache2/sites-available/your_domain_or_ip.conf

      <VirtualHost *:443>
         ServerName your_domain_or_ip
         DocumentRoot /var/www/your_domain_or_ip
      
         SSLEngine on
         SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
         SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key
      </VirtualHost>
      
      

      Veillez à mettre à jour la ligne ServerName en fonction de la manière dont vous avez l’intention de nommer votre serveur. Il peut s’agir d’un nom d’hôte, d’un nom de domaine complet ou d’une adresse IP. Assurez-vous que ce que vous choisissez correspond au Common Name (nom commun) que vous avez choisi lors de l’établissement du certificat.

      Les lignes restantes indiquent un répertoire DocumentRoot à partir duquel les fichiers seront servis, ainsi que les options SSL nécessaires pour faire pointer Apache vers notre certificat et notre clé nouvellement créés.

      Nous allons maintenant créer notre DocumentRoot et y insérer un fichier HTML à des fins de test :

      • sudo mkdir /var/www/your_domain_or_ip

      Ouvrez un nouveau fichier index.html avec votre éditeur de texte :

      • sudo nano /var/www/your_domain_or_ip/index.html

      Collez ce qui suit dans le fichier vierge :

      /var/www/your_domain_or_ip/index.html

      <h1>it worked!</h1>
      

      Ce n’est pas un fichier HTML complet, bien sûr, mais les navigateurs sont indulgents et cela suffira pour vérifier notre configuration.

      Enregistrez et fermez le fichier. Ensuite, nous devons activer le fichier de configuration avec l’outil a2ensite :

      • sudo a2ensite your_domain_or_ip.conf

      Ensuite, effectuons un test à la recherche d’éventuelles erreurs de configuration :

      • sudo apache2ctl configtest

      Si tout fonctionne correctement, vous obtiendrez un résultat qui ressemble à ceci :

      Output

      AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message Syntax OK

      La première ligne est un message vous indiquant que la directive ServerName n’est pas définie globalement. Si vous ne voulez plus voir ce message s’afficher, vous pouvez définir ServerName en spécifiant le nom de domaine ou l’adresse IP de votre serveur dans /etc/apache2/apache2.conf. Ceci est facultatif car le message ne fera pas de mal.

      Si votre sortie contient Syntax OK, votre fichier de configuration ne contient aucune erreur de syntaxe. Nous pouvons recharger Apache en toute sécurité pour que nos modifications soient appliquées :

      • sudo systemctl reload apache2

      Chargez maintenant votre site dans un navigateur, en veillant à utiliser https:// au début.

      Vous devriez voir une erreur. C’est normal pour un certificat auto-signé ! Le navigateur vous avertit qu’il ne peut pas vérifier l’identité du serveur, car notre certificat n’est signé par aucune de ses autorités de certification connues. Pour les tests et l’utilisation personnelle, cela peut être très bien. Vous devriez pouvoir cliquer pour accéder à des informations avancées ou complémentaires et choisir de poursuivre.

      Une fois que vous l’aurez fait, votre navigateur chargera le message it worked! .

      Remarque : si votre navigateur ne se connecte pas du tout au serveur, assurez-vous que votre connexion n’est pas bloquée par un pare-feu. Si vous utilisez ufw, les commandes suivantes ouvriront les ports 80 et 443 :

      • sudo ufw allow "Apache Full"

      Nous allons ensuite ajouter une autre section VirtualHost à notre configuration pour servir les requêtes HTTP simples et les rediriger vers HTTPS.

      Étape 4 — Redirection de HTTP vers HTTPS

      Actuellement, notre configuration ne répondra qu’aux demandes HTTPS sur le port 443. Il est bon de répondre également sur le port 80, même si vous voulez forcer le cryptage de tout le trafic. Mettons en place un VirtualHost pour répondre à ces demandes non cryptées et les rediriger vers le HTTPS.

      Ouvrez le même fichier de configuration Apache que celui que nous avons lancé lors des étapes précédentes :

      • sudo nano /etc/apache2/sites-available/your_domain_or_ip.conf

      En bas, créez un autre bloc VirtualHost pour faire correspondre les demandes sur le port 80. Utilisez la directive ServerName pour faire correspondre à nouveau votre nom de domaine ou votre adresse IP. Ensuite, utilisez Redirect (Rediriger) pour faire correspondre les requêtes et les envoyer au VirtualHost SSL. Veillez à inclure la barre oblique :

      /etc/apache2/sites-available/your_domain_or_ip.conf

      <VirtualHost *:80>
          ServerName your_domain_or_ip
          Redirect / https://your_domain_or_ip/
      </VirtualHost>
      

      Enregistrez et fermez ce fichier lorsque vous avez terminé, puis testez à nouveau la syntaxe de votre configuration, et rechargez Apache :

      • sudo apachectl configtest
      • sudo systemctl reload apache2

      Vous pouvez tester la nouvelle fonctionnalité de redirection en visitant votre site avec le simple http:// devant l’adresse. Vous devriez être redirigé automatiquement vers https://.

      Conclusion

      Vous avez maintenant configuré Apache pour servir des demandes cryptées en utilisant un certificat SSL auto-signé, et pour rediriger les demandes HTTP non cryptées vers HTTPS.

      Si vous envisagez d’utiliser SSL pour un site web public, vous devriez envisager d’acheter un nom de domaine et d’utiliser une autorité de certification largement reconnue telle que Let’s Encrypt.

      Pour plus d’informations sur l’utilisation de Let’s Encrypt avec Apache, veuillez lire notre tutoriel Comment sécuriser Apache avec Let’s Encrypt sur Ubuntu 20.04.



      Source link