简体   繁体   中英

AJAX request for data on the server in Express.JS to display in client?

I have been tasked to display this code on the client. I managed to load data/content on the page but its not so elegant .

 var express = require('express'); router = express.Router(), connect = require('connect'), urlParse = require('url').parse, fs = require('fs'); var iconList = fs.readFileSync('app/data/icons.list').toString().split('\\n').filter(function(site) { return site; }); var random = function(max) { return Math.floor(Math.random() * max); }; var icon2Site = function(icon) { var site = icon.replace(/_/g, '.').replace(/\\.png$/, ''); return site; }; var breaches = []; // breaches generation (function() { for (var i = 0; i < 1000; i++) { var index = random(iconList.length); breaches.push({ site: icon2Site(iconList[index]), date: Date.now() - 432000000 + random(432000000), number: random(100000) }); } })(); breaches.sort(function(a, b) { return a.date - b.date; }); var jsonResponse = function(res, code, body) { res.writeHead(code, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }); res.end(body); }; var foo = connect() .use(connect.logger('dev')) .use(function(req, res, next) { req.parsedUrl = urlParse(req.url, true); next(); }) .use(function(req, res, next) { if (req.parsedUrl.pathname !== '/ws/breaches') { return next(); } var index = parseInt(req.parsedUrl.query.index, 10) || 0; jsonResponse(res, 200, JSON.stringify({ result: breaches.slice(index, index + 20) })); }) .use(function(req, res, next) { if (req.parsedUrl.pathname !== '/ws/icon') { return next(); } var site = req.parsedUrl.query.site || ""; console.log(req.parsedUrl.query.site); site = site.replace(/\\./g, '_') + ".png"; jsonResponse(res, 200, JSON.stringify({ result: "https://s3-eu-west-1.amazonaws.com/static-icons/" + site })); }) .use(connect.static(__dirname + '/public', { maxAge: 1000 * 60 * 5 // Five minutes of cache })); router.get('/', function(req, res) { res.render('index', {pageID: 'mainData', breaches: breaches, iconList: iconList, sidebar: ['/images/vertbar.jpg'] }); console.log(breaches); console.log(iconList); }); module.exports = router; 

This is the crux of the task.

A friend of yours created a webservice to track these leaks and asked you to create a website to visualize them.

He created two different webservices:

  • GET /ws/breaches?index=[a positive integer] - This webservice returns an object with a "result" property containing an array of at most 20 breached sites, starting at the provided index (eg calling /ws/breaches?index=0 will return the 20 last breached sites, /ws/breaches?index=20 the 20 next, etc.) - A breached site object contains the following information: - site: The domain of the breached site - date: The time of the breach, in milliseconds - number: The number of accounts leaked

    • GET /ws/icon?site=[domain of a site]
      • This webservice returns the url of an icon for the provided site
      • The icons size is 58x36 pixels

I am using the Express and EJS frameworks to do so. However I am having a hard time with the following.

  1. How to pass the variables, objects from Express.js (the server) to the client.

This will get variables, objects etc. to the templates :

router.get('/', function(req, res) {
    res.render('index', {pageID: 'mainData', breaches: breaches, iconList: iconList, sidebar: ['/images/vertbar.jpg'] });
    console.log(breaches);
    console.log(iconList);
});

目录结构

I have a js file in my public folder (see image) called contentLoader.js where I guess I should make a AJAX request or something to fetch. But is that what I should be doing? Should I be getting the parameters of the ask above here?

var xmlhttp = new XMLHttpRequest();
var url = "index";

  xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
          var users = JSON.parse(xmlhttp.responseText).breaches;   
          // do something with the users variable that was passed by the routes
          console.log(users);
      }
  };

xmlhttp.open("GET", url, true);
xmlhttp.setRequestHeader('Accept', 'application/json');
xmlhttp.send();

So is my set-up or thinking correct? I know they're many ways to do something. But intuition is telling me I am supposed to use all that server code from the server, rather trying to pass it to a script on the client.

GET /ws/breaches?index=[a positive integer] - This webservice returns an object with a "result" property containing an array of at most 20 breached sites, starting at the provided index (eg calling /ws/breaches?index=0 will return the 20 last breached sites, /ws/breaches?index=20 the 20 next, etc.) - A breached site object contains the following information: - site: The domain of the breached site - date: The time of the breach, in milliseconds - number: The number of accounts leaked

If you look at the description, there are key parts (which I have bolded for you). It gives you the request method (GET), the path (/ws/breaches) + query string (?index=[a positive integer]), and the return value (an object).

When you set up a route in Express, you must specify the request method (which you have), a path (incorrect), and a response (incorrect). A response can be in different formats such as plain text, HTML, XML, and JSON. The latter is what you would typically use to send back an object. Express have convenient methods such as res.render() , res.send() , res.json() and others to send back response in proper formats. In your case, you would be using the latter res.json() as you want to send back an object.

In the description, it specifies what the object must contain: it must have a result property which is an array of sites (objects), each containing their own set of properties.

In the description, it also talks about the index which comes from the query string. To access that value, you would use req.query.index . So when you are building the object, you would need to do something with that value.

router.get('/ws/breaches', function(req, res) {
    // this is just an example of how the object would look;
    // you are most likely going to be building this object dynamically involving req.query.index
    let obj = {
        result: [
            {
                site: 'http://www.somedomain.com',
                date: 243,
                number: 2
            },
            { 
                site: 'http://www.anotherdomain.com',
                date: 312,
                number: 10
            },
            // etc
        ]
    };
    // send the response
    res.json(obj);
});

When it comes to the client code,

var url = "/ws/breaches?index=0"; // example
xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        var result = JSON.parse(xmlhttp.responseText).result;   
        // this should be an array of the sites
        console.log(result);
    }
};

I think you started off well. As you said, there's no right answer as many people set up their environment differently. Though, you probably should create a generic function for making AJAX calls, so that you don't repeat your code everywhere.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM