42

Q1) In my reactjs application, I am trying to fetch an API from my backend Nodejs server. The API responds with an image file on request.

I can access and see image file on http://192.168.22.124:3000/source/592018124023PM-pexels-photo.jpg

But in my reactjs client side I get this error on console log.

Uncaught (in promise) SyntaxError: Unexpected token � in JSON at position 0

Reactjs:

let fetchURL = 'http://192.168.22.124:3000/source/';
  let image = name.map((picName) => {
    return picName
  })

  fetch(fetchURL + image)
  .then(response => response.json())
  .then(images => console.log(fetchURL + images));

Nodejs:

app.get('/source/:fileid', (req, res) => {
const { fileid } = req.params;
res.sendFile(__dirname + /data/ + fileid); 
});

Is there any better way to do than what I am doing above?

Q2) Also, how can I assign a value to an empty variable (which lives outside the fetch function)
jpg = fetchURL + images; So I can access it somewhere.

JKhan
  • 889
  • 3
  • 13
  • 22
  • 2
    The image is not in JSON format. Did you mean to use `.blob()` or something rather than `.json()`? See https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch "Checking that the fetch was successful" section – CertainPerformance May 09 '18 at 07:59
  • You can't use `response.json()` to fetch an image cause it's not a json content. – Dario May 09 '18 at 08:00
  • @CertainPerformance Using blob I get this on console log: http://192.168.22.124:3000/source/[object Blob] – JKhan May 09 '18 at 08:02
  • Did you read the section in the link I posted? – CertainPerformance May 09 '18 at 08:03
  • you should encode the image in base64 in order to use it in json. – xanadev May 09 '18 at 08:04
  • @CertainPerformance I have read it and now I am getting some random strings: blob:http://localhost:3001/5970bae1-06a7-4882-a42e-63bb01a13f5f – JKhan May 09 '18 at 08:14
  • For what it is worth, if the response body of an API endpoint has a variety of content types, it would be more appropriate to check `Content-Type` in the response header to determine whether to invoke `response.json()` or `response.blob()` – Han Jul 20 '21 at 08:47

2 Answers2

89

The response from the server is a binary file, not JSON formatted text. You need to read the response stream as a Blob.

const imageUrl = "https://.../image.jpg";

fetch(imageUrl)
  //                         vvvv
  .then(response => response.blob())
  .then(imageBlob => {
      // Then create a local URL for that image and print it 
      const imageObjectURL = URL.createObjectURL(imageBlob);
      console.log(imageObjectURL);
  });
maxpaj
  • 5,149
  • 4
  • 29
  • 50
  • I get this on console log: 192.168.22.124:3000/source/[object Blob] – JKhan May 09 '18 at 08:11
  • Yes, because `images` is indeed a Blob now. Basically a file. You can then use `var url = URL.createObjectURL(images)` to create a URL for that image. – maxpaj May 09 '18 at 08:26
  • Now I get this: blob:http://localhost:3001/613348fe-52e4-4baa-8e76-e48332494e19 Am I still missing something? – JKhan May 09 '18 at 08:46
  • How can I access the image file url now? When I click on localhost:3001/613348fe-52e4-4baa-8e76-e48332494e19 I get redirected to my sign up page. – JKhan May 09 '18 at 08:58
  • You can't omit the `blob:` at the beginning of the URL. What do you want to do with the image? If you simply want to show it on the page, then why not just use a `` tag? – maxpaj May 09 '18 at 09:05
  • I am trying to save the blob in a variable outside the fetch which is not working and shows undefined. I am passing that variable to another component where it returns image like this – JKhan May 09 '18 at 09:13
  • Why not just pass the `fetchUrl + image` immediately to that component? Why do you need to fetch the image data at all? How do you see that the variable is `undefined` outside of the function? Using `console.log`? – maxpaj May 09 '18 at 09:17
  • Yes, console log. Assigning value to a variable that lives outside the fetch is undefined – JKhan May 09 '18 at 09:19
  • Could be that the `console.log` prints the variable before it is assigned inside the `fetch(...).then(...)` – maxpaj May 09 '18 at 09:22
  • this worked for me! thanks a lot, any tips on how i could cache that image? could i save it to local storage as a blob? – xunux Feb 08 '19 at 03:10
  • 1
    You can save the blob as a Base64 encoded string in local storage. Check out https://stackoverflow.com/questions/18650168/convert-blob-to-base64 – maxpaj Feb 08 '19 at 07:18
1

Equivalent to solution by @maxpaj, but using async and await.

async function load_pic() {
    
        const url = '<REPLACE-WITH-URL>'
    
        const options = {
            method: "GET"
        }
    
        let response = await fetch(url, options)
    
        if (response.status === 200) {
            
            const imageBlob = await response.blob()
            const imageObjectURL = URL.createObjectURL(imageBlob);
    
            const image = document.createElement('img')
            image.src = imageObjectURL
    
            const container = document.getElementById("your-container")
            container.append(image)
        }
        else {
            console.log("HTTP-Error: " + response.status)
        }
    }
eric.mcgregor
  • 3,176
  • 2
  • 13
  • 12