Reputation: 1287
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.
Upvotes: 72
Views: 214828
Reputation: 6771
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));
}
Upvotes: 131
Reputation: 8835
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>
StackOverflow uses a sandboxed iframe
's so we cannot test the download here, but you can use my codepen
Upvotes: 5
Reputation: 3653
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)
}
}
Upvotes: 13