0

I've been trying to fetch multiple images through URLs in the server and try to display them in the browser. When I click the run button, I know images have been fetched by the server through console log (which shows the two buffer items), but nothing shows up in the browser.

I understand that I can fetch directly from the browser, but eventually I'll have to fetch from the URLs saved in the database, so ideally I could fetch from the server, and display the images in the browser.

Below is the code.

Any help or insights would be greatly appreciated!

Browser:

console.log('running')
 var outside
document.getElementById('getLogos').addEventListener('click',getLogos);
 
function getLogos(){
fetch('http://localhost:8080/logos'
)
// .then((res) => res.blob())
.then((data) => {
 let imagesInfo = JSON.parse(data);
 let pics = "";
 for (i=0;i<imagesInfo.length;i++){
  // document.write("<li><img src='" + images[i] + "' width='160' height='120'/><span>" + images[i] + "</span></li>");
  pics += `
  <li><img src='" + images[i] + "' width='160' height='120'/><span>" + images[i] + "</span></li>
  `
   }
 // outside = URL.createObjectURL(images)
 
document.getElementById('output').innerHTML = pics;
  console.log(images)
  console.log(imagesInfo)
})
}
<!DOCTYPE html>
<html>

<body>
  <h1>Logos</h1>
  <ul id="logos">
    <button id="getLogos">Get Logos</button>
  </ul>
  <div id="output"></div>
</body>

</html>

Server - node

    console.log('server is starting');

const express = require('express');
const morgan = require('morgan');
const app = express();
//const mysql = require('mysql');

const request = require('request');

app.use(express.static('./public'));

app.listen(8080, () => {
  console.log("Listening on 8080")
})

app.use(morgan('short'));


app.get("/logos", (req, res, next) => {

  var options = [
    {
    url: "https://www.google.com/images/srpr/logo11w.png", ///url will be sourced from a database
    method: 'GET',
    headers: {'Content-Type': 'image/png'},
    encoding: null
  },
    {
      url: "https://logos-download.com/wp-content/uploads/2016/02/Walmart_logo_transparent_png.png",
      method: 'GET',
      headers: {'Content-Type': 'image/png'},
      encoding: null
    }
  ]

  var result = [];
  options.forEach(function (option) {
      request(option, function (err, body) {
          if (err) {
              console.log(err)
              return;
          } else
          // console.log(body.body)
              result.push(body.body);
              console.log(result)
              resultString = JSON.stringify(result)
              res.write (resultString);
              res.end        
      })

  })

})

Before stringify - sent as buffer in node

After stringify - sent as string in node

SnowKari
  • 37
  • 1
  • 7

3 Answers3

0

First, just have a one GET petition

app.get("/logos", (req, res, next) => {

}

Inside this, group all options in array,

var options = [
    {
        url: "https://www.google.com/images/srpr/logo11w.png", ///url will be sournced from a database
        method: 'GET',
        headers: { 'Content-Type': 'image/png' },
        encoding: null
    },
    {
        url: "https://logos-download.com/wp-content/uploads/2016/02/Walmart_logo_transparent_png.png",
        method: 'GET',
        headers: { 'Content-Type': 'image/png' },
        encoding: null
    }
];

Then, do a foreach for process all the options, and save the result into an array for example:

var result = [];
options.forEach(function (option) {
    request(option, function (err, body) {
        if (err) {
            console.log(err)
            return;
        } else
            result.push(body.body);
    })
})

Then, return an array with all of your logos

result = JSON.stringify(result);
res.write(result)

And now you will have your JSON in stringify format.

For transform to an a Object again, use

var myjsonagain = JSON.parse(resultstringifyed)

And you can read for example with array map. (I use Object.keys for transform it to array because currently is a Object)

Object.keys(myjsonagain).map(item => ...

Jordi Castillo
  • 683
  • 1
  • 5
  • 13
  • Thanks a lot for the answer, I will try it now. So in browser, you meant I should do another foreach to read all logos? – SnowKari Mar 13 '19 at 20:12
  • Yes, you will recibe an array, you have to do any method for read this array like foreach, for, while, array map ... Let me know if this works! – Jordi Castillo Mar 13 '19 at 20:59
  • Hi @Jordi, I have updated my question. In server, code did not work due to array cannot be used in res.write (error: First argument must be a string or Buffer), then I tried to convert array to buffer while using res.write, buffer was sent as JSON to the browser, still didn't work. Also I updated browser code with a loop, but images still not showing up in the browser. Can you please shed some more lights to what might have gone wrong? Thanks a million! – SnowKari Mar 14 '19 at 03:12
  • Added JSON.stringify line! Then for read a json with loop check for example my answer here https://stackoverflow.com/a/55137147/10750663 – Jordi Castillo Mar 14 '19 at 09:05
  • Thank you Jordi for updating your response! I'm still trying to figure it out by what both you and Jeff said, will get back to this post either if I get or still don't get it. Thank you again! – SnowKari Mar 14 '19 at 22:15
  • Hi Jordi, I have updated my question again. After image data is stringified and sent to browser, I ran localhost:8080/logos, it became a very long array format buffer, is this expected? Since when the image data was sent as buffer, at least the first picture showed up in localhost:8080/logos. Also, after I stringified the image data, still nothing shows up in the browser when i ran localhost:8080. Is this a problem with my code in browser or node? Thanks so much!! – SnowKari Mar 15 '19 at 02:56
  • I just posted two snippets, first one is when image is sent as buffer (body.body) in nodejs, second one is when image is sent as string (resultString), when i ran localhost:8080/logos. Is the latter expected to show like in the picture? Thanks a lot! – SnowKari Mar 15 '19 at 03:05
  • @SnowKari i edited the answer, please tell us if it works! – Jordi Castillo Mar 15 '19 at 08:28
  • Hello @Jordi, thanks a lot for your response. I have tried your code, but I'm wondering why we would transform result into an Object again by using JSON.parse? And since it's again not a string or buffer, res.write would not work. Also Object.Keys is only getting the names of the object, why would we need that in the browser to get images sent from server? Thanks so much!! – SnowKari Mar 18 '19 at 21:16
  • @SnowKari First considere to give points to persons to try to help you in stackoverflow, this is important for a lot of developers. I will try to explain better: First you have an Object, but you can't send and object in res.write, so you stringify it. After it, when you recieve in your object stringlified, you can't work with it, so you will convert it as an object again. After this, you can do whatever you want for work with your Object, for example with `Object.keys(myjsonagain).map(item => ...` , for read "key" you can use `myjsonagain[item]` into Object.keys.map . – Jordi Castillo Mar 18 '19 at 22:32
  • Thanks Jordi for your time. I had given you points by voting it up. Just to clarify, for the following two lines you meant to include in the browser code, correct? var myjsonagain = JSON.parse(resultstringifyed) Object.keys(myjsonagain).map(item => ... – SnowKari Mar 20 '19 at 02:12
  • Jordi, is it because i don't have enough reputation that's why it doesnt show? – SnowKari Mar 20 '19 at 13:34
  • @SnowKari I think your reputation dosen't care here, you can vote response as valid with green check, and give votes with arrow up into my answer. – Jordi Castillo Mar 20 '19 at 18:15
0

One way you can do this on client side is to get get image from the server and convert it to data image and append it to your element this way. So client can grab, and incorporate contents without your server interaction.

Be careful, you need to make sure that your browser can handle data images by making sure your Content Security Policy allows it.

This could do:

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:;"
\>
HelpNeeder
  • 6,383
  • 24
  • 91
  • 155
  • Hi HelpNeeder, is there any links to show how to get image on the client side from the server? Thanks! – SnowKari Mar 15 '19 at 03:07
  • There are few ways to do it, one way to do it is explained in [this article](https://davidwalsh.name/convert-image-data-uri-javascript). I don't know if you're using your own server to serve you images or not, but if sp, you can make your server serve you image in data-image format through AJAX. – HelpNeeder Mar 19 '19 at 23:51
0

You need to make sure that your code for src is a valid text URL string. When you put a buffer into it, the browser can't interpret it. Avoid buffers unless you really need it. As Jordi said in his answer. Take the URL (either in an object or array) then JSON.stringify it and send it to the browser. Then Convert it back to an object or array. Then you can put it into the src for the image

//incoming stringified json "[{url: 'some url', name: 'cat picture'}]"
document.getElementById('getLogos').addEventListener('click',getLogos);

function getLogos(){
fetch('http://localhost:8080/logos') //This should return a stringified array or object
.then((data) => {
    let imageInfo = JSON.parse(data);
    let text = "";
    for (i=0;i<images.length;i++){
        text += `<li><img src='" + images[i].url + "' width='160' height='120'/><span>" + images[i].name + "</span></li>`
        } //src needs to be a string that is a valid url, i bet if you use the inspector this would be a long buffer string that the browser could not parse

    document.getElementById('output').innerHTML = pics;
        console.log(images)
  })
}

for most things in the browser, try to use JSON or strings. Buffers are usually not needed unless you sending complicated data back and forth. And the browser usually handles pictures just fine.

Jeff
  • 36
  • 1
  • Thank you Jeff, I will try what you have said and get back to you. – SnowKari Mar 14 '19 at 22:15
  • Hi Jeff, did you mean i should send all URLs pulled by the server in a string/json.format and let the browser does the fetch work for all images? – SnowKari Mar 15 '19 at 03:09
  • Yes, If your pulling a list of pictures, then give it an object or an array with the urls in it. The browser knows how to handle pictures. And it can cache them properly. when the browser requests the url, ie HTTP://localhost:8080/image// {some image name}, you just send the image, and the browser will know that to apply that as an image. If you are using Express.js then you just have to point express's static directory at your picture folder, app.use(express.static('./images'), and express will server those images automatically. Or use an external reference for the pictures – Jeff Mar 15 '19 at 09:32
  • i just looked at your code again, and you can ignore the express.static, since you are getting the images from a location other than your server. – Jeff Mar 15 '19 at 09:36
  • Hi Jeff, thanks a lot for your response. I will try your way as my last resort if I can't figure out how to send images directly from the server. Thanks so much! – SnowKari Mar 18 '19 at 21:17