Issue Retrieving Files from Azure Storage

Issue

I am working on a web application that allows users to store and retrieve files using Azure Storage. Currently, I am facing a problem when trying to retrieve the files from Azure Storage. I have implemented the Azure Blob Storage SDK to handle interactions with Azure Storage.

Frontend:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const Filelist = () => {
  const [files, setFiles] = useState([]);

  useEffect(() => {
    const fetchFiles = async () => {
      try {
        const response = await axios.get('http://localhost:3000/api/filelist');
        setFiles(response.data);
      } catch (error) {
        console.error('Error fetching files:', error);
      }
    };

    fetchFiles();
  }, []);

  async function downloadFile(filename) {
    try {
      const response = await axios.post('http://localhost:3000/api/display-file', {
        filename,
      });
    } catch (error) {
      console.error('Error downloading file:', error);
    }
  }

  return (
    <div>
      <h2>Files:</h2>
      <ul>
        {files.map((file) => (
          <li key={file._id}>
            <a href={file.fileURL} target="_blank" rel="noopener noreferrer">
              {file.filename}
            </a>
            <button onClick={() => downloadFile(file.filename)}>Download</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default Filelist;

Backend:

exports.displayFile = async (req, res) => {
  try {
  const storageAccount = process.env.AZURE_STORAGE_ACCOUNT_NAME;
  const containerName = process.env.AZURE_CONTAINER_NAME;
  const accessKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;
  const connectionString = process.env.AZURE_CONNECTION_STRING;

  const blobService = azure.createBlobService(connectionString);
  const blobName = req.filename; 

  
    var downloadedFileName = util.format('%s/CopyOf%s', blobName);
    blobService.getBlobToLocalFile(containerName, blobName, downloadedFileName, function (error, serverBlob) {
      if (error) {
        console.error('Error downloading blob:', error);
      } 
    });
  } catch (error) {
    console.log(error);
    res.send(401);
  }
};

exports.fileList = async (req, res) => {
  try {
    const files = await File.find();
    return res.status(200).json(files);
  } catch (error) {
    console.error('Error fetching files:', error);
    return res.status(500).json({ error: 'Internal server error!' });
  }
}

I am using the azure-storage library to interact with Azure Blob Storage and download the files. However, when I attempt to retrieve the PDF files using the getBlobToLocalFile method, I encounter the "ArgumentNullError: Required argument blob for function getBlobToLocalFile is not defined" error.

Solution

I made some changes to your code and can able to upload and download files in the storage account container from Azure Portal.

Code:

frontend/src/components/FileList.js:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const FileList = () => {
  const [files, setFiles] = useState([]);

  useEffect(() => {
    const fetchFiles = async () => {
      try {
        const response = await axios.get('http://localhost:3000/api/filelist');
        setFiles(response.data);
      } catch (error) {
        console.error('Error fetching files:', error);
      }
    };

    fetchFiles();
  }, []);

  async function downloadFile(filename) {
    try {
      const response = await axios.post(
        'http://localhost:3000/api/display-file',
        { filename },
        { responseType: 'blob' }
      );

      const blob = new Blob([response.data]);
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      window.URL.revokeObjectURL(url);

      console.log('File downloaded:', filename);
    } catch (error) {
      console.error('Error downloading file:', error);
    }
  }

  return (
    <div>
      <h2>Files:</h2>
      <ul>
        {files.map((file) => (
          <li key={file._id}>
            <a href={file.fileURL} target="_blank" rel="noopener noreferrer">
              {file.filename}
            </a>
            <button onClick={() => downloadFile(file.filename)}>Download</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default FileList;

backend/controllers/fileController.js:

const azure = require('azure-storage');
const fs = require('fs');
const path = require('path');

const storageAccount = "<storage_name>";
const containerName = "<container_name>";
const accessKey = "<storage_key>";
const connectionString = "<connec_string>";

const blobService = azure.createBlobService(connectionString);

exports.displayFile = async (req, res) => {
  try {
    const blobName = req.body.filename;
    res.setHeader('Content-Disposition', `attachment; filename=${blobName}`);
    res.setHeader('Content-Type', 'application/pdf');
    blobService.getBlobToStream(containerName, blobName, res, function (error) {
      if (error) {
        console.error('Error downloading blob:', error);
        return res.status(500).json({ error: 'Error downloading blob!' });
      }
    });
  } catch (error) {
    console.log(error);
    return res.status(401).json({ error: 'Unauthorized' });
  }
};

exports.fileList = async (req, res) => {
  try {
    const files = [
      { _id: 1, filename: '<file1_name>.pdf', fileURL: 'https://<storage_name>.blob.core.windows.net/<container_name>/<file1_name>.pdf' },
      { _id: 2, filename: '<file2_name>.pdf', fileURL: 'https://<storage_name>.blob.core.windows.net/<container_name>/<file2_name>.pdf' },
    ];

    return res.status(200).json(files);
  } catch (error) {
    console.error('Error fetching files:', error);
    return res.status(500).json({ error: 'Internal server error!' });
  }
};

backend/app.js:

const express = require('express');
const cors = require('cors');
const multer = require('multer');
const apiRouter = require('./routes/api');
const azure = require('azure-storage');
const path = require('path');

require('dotenv').config();

const app = express();
app.use(express.json());
app.use(cors());

const storageAccount = "<storage_name>";
const containerName = "<container_name>";
const accessKey = "<storage_key>";
const connectionString = "<connec_string>";

const blobService = azure.createBlobService(connectionString);
const storage = multer.memoryStorage();
const upload = multer({ storage });

app.use('/api', apiRouter);
app.post('/api/upload-file', upload.single('file'), (req, res) => {
  const file = req.file;
  if (!file) {
    return res.status(400).json({ error: 'No file uploaded' });
  }

  const blobName = file.originalname;
  const container = containerName;
  blobService.createBlockBlobFromText(container, blobName, file.buffer, (error, result, response) => {
    if (error) {
      console.error('Error uploading blob:', error);
      return res.status(500).json({ error: 'Error uploading blob to Azure' });
    }
    console.log('File uploaded to Azure:', blobName);
    res.sendStatus(200);
  });
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Output:

Firstly, we should run the backend code and it runs successfully as below,

enter image description here

Then, I run the frontend code and it also runs successfully as below,

enter image description here

And it opens in the browser like below. I click on Choose File to choose a file that I want to upload and then click on Upload,

enter image description here

I uploaded another file like the same as below,

enter image description here

Above two files were uploaded successfully to the storage account container as a blob-like below in the VS code terminal,

enter image description here

The two files uploaded successfully to the storage account container as a blob at the Azure Portal like below,

enter image description here

Then, I click on the Download button in Files, and those files downloaded successfuly as below,

enter image description here

Answered By – Dasari Kamali

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published