69

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.

7

3 Answers 3

125

The response from the server is an image file, not JSON formatted text. You'll want to read the response content as a Blob ("binary large object"), with Response.blob().

In this function we fetch a blob:

async function fetchBlob(url) {
    const response = await fetch(url);

    // Here is the significant part 
    // reading the stream as a blob instead of json
    return response.blob();
}

Then, you can create an object URL and assign the source of an image to this generated URL in your React application:

const [imageSourceUrl, setImageSourceUrl] = useState("");

const downloadImageAndSetSource = async (imageUrl) => {
    const image = await fetchBlob(imageUrl);
    setImageSourceUrl(URL.createObjectURL(image));
}
11
  • I get this on console log: 192.168.22.124:3000/source/[object Blob]
    – JKhan
    Commented May 9, 2018 at 8: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
    Commented May 9, 2018 at 8:26
  • Now I get this: blob:localhost:3001/613348fe-52e4-4baa-8e76-e48332494e19 Am I still missing something?
    – JKhan
    Commented May 9, 2018 at 8: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
    Commented May 9, 2018 at 8:58
  • 1
    You can save the blob as a Base64 encoded string in local storage. Check out stackoverflow.com/questions/18650168/convert-blob-to-base64
    – maxpaj
    Commented Feb 8, 2019 at 7:18
12

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)
        }
    }
5

This question is 4 years old and I think in 2022 there are many ways to solve this. This is ES6 version using async calls.

First, I don't know if you are trying to download the image or insert the image into a img tag. So I will assume we want to download the image.

The process is simple: a) fetch the image as a blob; b) convert blob to Base64 using URL.createObjectURL(blob); and c) trigger the download using a ghost a tag.

const $btn = document.getElementById('downloadImage')
const url = 'https://s3-ap-southeast-1.amazonaws.com/tksproduction/bmtimages/pY3BnhPQYpTxasKfx.jpeg'

const fetchImage = async url => {
  const response = await fetch(url)
  const blob = await response.blob()
  
  return blob
}

const downloadImage = async url => {
  const imageBlob = await fetchImage(url)
  const imageBase64 = URL.createObjectURL(imageBlob)

  console.log({imageBase64})
  
  const a = document.createElement('a')
  a.style.setProperty('display', 'none')
  document.body.appendChild(a)
  a.download = url.replace(/^.*[\\\/]/, '')
  a.href = imageBase64
  a.click()
  a.remove()
}

$btn.onclick = event => downloadImage(url)
<button id="downloadImage">Download Image</button>

Note:

StackOverflow uses a sandboxed iframe's so we cannot test the download here, but you can use my codepen

2
  • what if i want to show image in <img> tag ?
    – Ali
    Commented Nov 14, 2022 at 8:29
  • just load the imageBase64 on a img or canvas tag.
    – Teocci
    Commented Nov 14, 2022 at 9:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.