I am trying to POST images to Azure from my Next.js application.
I have created an account on Azure, created a container and I am able to upload images, however when I try to view the image on Azure it either displays binary data (if I don't set the content-type) or a broken image symbol (if I set the content-type to 'image/jpeg' - I only try to upload jpeg files for now). The access level of the container and blobs is set to "Container" so it should be possible to view the images. When I click on the URL created by Azure (for instance https://wilmaenstrom.blob.core.windows.net/wilmascontainer/example-14), I get this error in the console: "Failed to load resource: the server responded with a status of 400 (One of the request inputs is out of range.)"
Does anyone have an idea what I need to change to display the images in Azure/browser?
This is how I upload the image from the client:
const ImageUploadForm = () => {
const [image, setImage] = useState<any>();
const handleSubmit = async (e) => {
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onload = () => {
setImage(reader.result);
};
reader.onerror = () => {
console.log('reader.error', reader.error);
};
};
const uploadImage = async () => {
try {
const headers = {
'Content-Type': 'image/jpeg',
};
const response = await fetch('/api/postImage', {
method: 'POST',
body: image,
headers: headers,
});
if (response.ok) {
console.log('Image uploaded successfully!');
} else {
console.error('Image upload failed.');
}
} catch (error) {
console.error('Error uploading image:', error);
}
};
return (
<>
<input type="file" accept="image/*" onChange={handleSubmit} />
<button onClick={uploadImage}\>Ladda upp bild</button>
</>
);
};
This is my postImage api route:
import azureStorage from '../../app/lib/azureConnection';
export async function postImage(req: NextApiRequest, res: NextApiResponse) {
try {
const fileBuffer = Buffer.from(req.body, 'base64');
const fileName = 'example-14';
const imageUrl = await azureStorage.uploadImageToAzureStorage(fileBuffer, fileName, req.headers['content-type']);
res.status(200).json(imageUrl);
} catch (error) {
console.log('error', error);
}
}
This is the azureStorage function:
import { BlobServiceClient } from '@azure/storage-blob';
const connectionString = process.env.AZURE_CONNECTION;
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString as string);
const containerName = 'wilmascontainer';
async function uploadImageToAzureStorage(fileBuffer, fileName, headers) {
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
const blobHTTPHeaders = { blobContentType: headers };
await blockBlobClient.uploadData(
fileBuffer, {
blobHTTPHeaders,
},
);
return blockBlobClient.url;
}
I made some changes to your code to upload the jpeg image file to Azure Storage and saw the image file with the blob URL from storage.
Code:
app/lib/azureConnection.js :
import { BlobServiceClient } from '@azure/storage-blob';
const connectionString = process.env.AZURE_CONNECTION;
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString);
const containerName = process.env.AZURE_CONTAINER_NAME;
async function uploadImageToAzureStorage(fileBuffer, fileName, contentType) {
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
try {
await blockBlobClient.uploadData(
fileBuffer,
{
blobHTTPHeaders: { blobContentType: contentType },
}
);
return blockBlobClient.url;
} catch (error) {
console.error('Error uploading image:', error);
throw error;
}
}
export { uploadImageToAzureStorage };
components/ImageUploadForm.js :
import { useState } from 'react';
const ImageUploadForm = () => {
const [image, setImage] = useState(null);
const handleSubmit = (e) => {
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onload = () => {
setImage(reader.result);
};
reader.onerror = () => {
console.log('reader.error', reader.error);
};
};
const uploadImage = async () => {
try {
const headers = {
'Content-Type': 'image/jpeg',
};
const response = await fetch('/api/postImage', {
method: 'POST',
body: image,
headers: headers,
});
if (response.ok) {
console.log('Image uploaded successfully!');
} else {
console.error('Image upload failed.');
}
} catch (error) {
console.error('Error uploading image:', error);
}
};
return (
<>
<input type="file" accept="image/*" onChange={handleSubmit} />
<button onClick={uploadImage}>Upload Image</button>
</>
);
};
export default ImageUploadForm;
pages/api/postImage.js :
import * as azureStorage from '../../app/lib/azureConnection';
export default async function postImage(req, res) {
try {
const fileBuffer = Buffer.from(req.body.replace(/^data:image\/\w+;base64,/, ''), 'base64');
const fileName = 'example-14';
const imageUrl = await azureStorage.uploadImageToAzureStorage(fileBuffer, fileName, req.headers['content-type']);
res.status(200).json(imageUrl);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Image upload failed' });
}
}
pages/index.js :
import ImageUploadForm from '../components/ImageUploadForm';
const Home = () => {
return (
<div>
<h1>Image Upload to Azure Blob Storage</h1>
<ImageUploadForm />
</div>
);
};
export default Home;
.env.local :
AZURE_CONNECTION="<connec_string>"
AZURE_CONTAINER_NAME="<container_name>"
Output :
The above code runs successfully as below:
I got the below in the browser with the above output URL.
Then, I click on Choose File to choose a jpeg image file and click on Upload Image as below.,
The jpeg image file was uploaded successfully to the storage account container at the Azure portal as below.
With the blob URL also, I saw the jpeg image blob in the browser as below.