2 votes

Comment faire des appels asynchrones avec express et node

J'ai une petite application qui demande à l'utilisateur sa ville et renvoie les données météorologiques actuelles. Lorsque l'utilisateur clique sur la fonction "Get Weather", celle-ci extrait le Json de l'api OpenWeatherMap et le renvoie à l'utilisateur. Pour l'instant, la page est rafraîchie et les données sont affichées. Que dois-je changer pour qu'au lieu de rafraîchir la page, elle se charge de manière asynchrone chaque fois que vous changez de ville ?

Server.js (routage Express)

const express = require('express');
const bodyParser = require('body-parser');
const weatherFunctions = require('./functions/weatherFunctions.js')
const PORT = process.env.PORT || 5000
const app = express()

app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs')

app.get('/', (req, res) => {
    res.render('index', {weather: null, error: null});
})

app.post('/', weatherFunctions.getWeather)

app.listen(PORT, () => console.log(`Listening on ${ PORT }`))

weatherFunctions.js

const request = require('request');
const apiKey = '28af81603ac21f0fe4c75478dad21818';

function currentWeather(req, res) {

    let city = req.body.city;
    let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}`

    request(url, function (err, response, body) {
        if (err) {
            res.render('index', {
                weather: null,
                error: 'Error, please try again'
            });
        } else {
            let weather = JSON.parse(body)
            if (weather.main == undefined) {
                res.render('index', {
                    weather: null,
                    error: 'Error, please try again'
                });
            } else {
                let weatherText = `It's ${weather.main.temp} degrees in ${weather.name}! `;
                weatherText += `The low for today will be ${weather.main.temp_min} degrees with a high of ${weather.main.temp_max}`;
                res.render('index', {
                    weather: weatherText,
                    error: null
                }); //passes parameters for ejs to read
            }
        }
    });
}

module.exports = {
    getWeather: currentWeather
};

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Simple Weather</title>
    <link rel="stylesheet" type="text/css" href="stackoverflow.com/css/style.css">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300' rel='stylesheet' type='text/css'>
  </head>
  <body>
    <div class="container">
      <fieldset>
        <form action="/" method="post">
          <input name="city" type="text" class="ghost-input" placeholder="Enter a City" required>
          <input type="submit" class="ghost-button" value="Get Weather">
        </form>
        <% if(weather !== null){ %>
          <p><%= weather %></p>
        <% } %>

        <% if(error !== null){ %>
          <p><%= error %></p>
        <% } %>
      </fieldset>
    </div>
  </body>
</html>

1voto

Matt Oestreich Points 3154

La raison pour laquelle il est rafraîchi pour vous est que vous rendez le HTML côté serveur. Vous devrez tirer parti de XMLHttpRequest (alias XHR) . Vous pouvez utiliser un wrapper XHR appelé fetch ce qui facilite grandement le travail avec XHR.

L'obtention de données API à l'aide d'un navigateur, puis la modification du DOM à l'aide de ces données, est connue sous le nom de "rendu côté client"

Par exemple, si vous ouvrez la console de votre navigateur et y collez le code suivant, vous verrez comment vous pouvez envoyer des requêtes depuis votre navigateur et recevoir des données en retour (c'est la base du rendu côté client) :

fetch(`https://api.openweathermap.org/data/2.5/weather?q=New York&units=imperial&appid=28af81603ac21f0fe4c75478dad21818`).then(res => res.json()).then(data => console.log(data));

Voir l'exemple suivant :

document
  .getElementById("getWeather")
  .addEventListener("click", () => {
    handleGetWeather();
  });

async function handleGetWeather() {
  const apiKey = "28af81603ac21f0fe4c75478dad21818";
  const locationEl = document.getElementById("location");
  const weatherDataEl = document.getElementById("weatherData");

  const results = await currentWeather(locationEl.value, apiKey);
  weatherDataEl.innerHTML = results;
}

async function currentWeather(location, apiKey) {
  const city = location.replace(/\s\s+/g, ' '); // Replace multiple spaces with single space
  if (city === "" || city === " ") return `<pre>Please enter a location!</pre>`;
  let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}`;
  try {
    const res = await fetch(url);
    if (res.ok === false) {
      return `<pre><i>Location '${encodeURIComponent(city)}' not found!</i></pre><br/><pre>Full Error: ${res.statusText}</pre>`;
    }
    const weather = await res.json();
    const main = weather.main;
    const t = Number(main.temp) >= 71.00 ? 'hot' : 'cold';
    const min = Number(main.temp_min) >= 71.00 ? 'hot' : 'cold';
    const max = Number(main.temp_max) >= 71.00 ? 'hot' : 'cold';
    return `
      <h1>
        It's <span class="${t}">${main.temp}</span> degrees in ${weather.name}!
      </h1>
      <h1>
        The low for today will be 
        <span class="${min}">${main.temp_min}</span>
        degrees with a high of 
        <span class="${max}">${main.temp_max}</span>
      </h1>
    `;
  } catch {
    return `<pre><i>Error, please try again.</i></pre>`;
  }
}

pre {
  color: red;
  margin-bottom: -15px;
}

.hot {
  color: red;
}

.cold {
  color: blue;
}

<input id="location" />
<button id="getWeather">Get Weather</button>
<div id="weatherData"></div>

0voto

jfriend00 Points 152127

Pour charger une nouvelle ville sans rafraîchir la page, voici un aperçu de ce que vous feriez :

  1. Accrochez le Javascript côté client dans votre page pour qu'il intercepte la soumission du formulaire plutôt que de laisser le navigateur soumettre le formulaire.

  2. Envoyez le formulaire à votre serveur via un appel Ajax à partir de votre page Javascript (probablement à l'aide de l'outil côté client). fetch() interface.

  3. Modifiez le gestionnaire POST du serveur pour qu'il rende un morceau de votre page (le morceau qui change), et non la page entière.

  4. Récupérez les résultats de l'appel ajax dans votre Javascript et remplacez une partie du contenu de la page par la partie nouvellement rendue en utilisant des manipulations DOM (probablement en définissant le paramètre .innerHTML d'un objet parent particulier dans votre page).

Vous avez deux approches pour le fonctionnement de l'appel Ajax. Vous pouvez soit récupérer un morceau de HTML rendu sur le serveur et insérer ce HTML dans la page (en remplaçant un HTML précédent), soit récupérer des données JSON avec l'appel Ajax et les rendre en HTML dans le navigateur, puis insérer ce HTML. Vous aurez besoin d'une version côté client de votre modèle de rendu pour pouvoir utiliser la deuxième option.


Pour votre information, je ne comprends pas pourquoi vous avez fait du mot "asynchrone" une si grande partie de votre question. Presque tout ici est déjà asynchrone. Même l'affichage de votre formulaire dans la version actuelle de votre page est déjà asynchrone et si vous le modifiez comme ci-dessus, l'affichage via Javascript sera également asynchrone.

0voto

JRichardsz Points 1487

Réponse rapide

Vous devez consommer le api.openweathermap directement à partir de votre page en utilisant javascript et ajax (frontrend), plutôt qu'à travers nodejs dans votre (backend)

Explication

Dans le développement web, il existe deux approches pour fournir du contenu aux utilisateurs finaux, appelées Rendu du serveur et rendu du côté client

Rendu côté serveur (SSR) - Avec la méthode de rendu traditionnelle, toutes les ressources de votre page sont hébergées sur le serveur. Ensuite, lorsque la page est demandée (généralement par les navigateurs Web), les fichiers Html, JS et CSS sont téléchargés. Les frameworks peuvent également créer dynamiquement le html sur la base d'une logique dorsale et enfin le télécharger.

Technologies : java, c#, python, nodejs, etc.

Rendu côté client (CSR) - une méthode de rendu plus récente, qui repose sur l'exécution de JS du côté client (navigateur) via un framework JavaScript. Ainsi, lorsque la page est demandée, un index.html, des css et des js minimaux, peu nombreux ou vides, sont téléchargés. Voici javascript est responsable de l'envoi ou de la réception de données et de la mise à jour d'une section minimale de la page. sans rafraîchir la page entière. . Enfin, lorsque l'utilisateur clique ou déclenche un événement, javascript enverra ou recevra l'adresse de l'utilisateur. données communément vers un rest api (json) en utilisant un appel asynchrone ( ajax ).

Technologies : react, angular, vue, aurelia, jquery, pure javascript, etc.


Dans votre cas, vous utilisez nodejs qui est un langage backend et cadre ejs qui crée dynamiquement le html dans votre backend, en d'autres termes : Rendu du serveur

Enfin, si vous ne voulez pas l'effet de rafraîchissement de la page entière, vous pouvez ajouter un javascript dans votre application nodejs comme simple ressource à télécharger dans la section de votre site web. index.ejs et ou au bas de votre

Ce javascript doit détecter le sur la page complètement chargée pour charger des données ou lier une fonction javascript à votre . Vous pouvez utiliser :

  • jquery :
  • XMLHttpRequest
  • aller chercher
  • axios

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