Jack
Jack

Reputation: 491

Need to fix code for uploading and downloading images from azure blobs with nodejs

I am trying to write a nodejs app that uploads images to an azure blob so that then another program can connect to the DB and download the image.

I am having trouble with the code I got from the blobs api. I think the upload is working properly but I dont seem to be able to download the image from the given URL.

async function execute() {

    const containerName = "a00008";
    const blobName = "myBlob";
    const content = "./sun.png";
    const localFilePath = "./sun.png";

    const credentials = new SharedKeyCredential(STORAGE_ACCOUNT_NAME, ACCOUNT_ACCESS_KEY);
    const pipeline = StorageURL.newPipeline(credentials);
    const serviceURL = new ServiceURL(`https://${STORAGE_ACCOUNT_NAME}.blob.core.windows.net`, pipeline);

    const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);

    const aborter = Aborter.timeout(30 * ONE_MINUTE);


    await showContainerNames(aborter, serviceURL);

    await containerURL.create(aborter);


    await uploadLocalFile(aborter, containerURL, content);
    console.log(`Local file "${content}" is uploaded`);

    await uploadStream(aborter, containerURL, localFilePath);
    console.log(`Local file "${localFilePath}" is uploaded as a stream`);




    const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, content);
    console.log("The blobs URL is: " + JSON.stringify(blockBlobURL.url));

    const downloadResponse = await blockBlobURL.download(aborter, 0);
    downloadedContent = downloadResponse.readableStreamBody.read(content.length)
    console.log(`Downloaded blob content: "${downloadedContent}"`);}

    execute().then(() => console.log("Done")).catch((e) => console.log(e));

Here is the code for uploadLocalFile and uploadLocalStream they are directly taken from MS azure docs:

async function uploadLocalFile(aborter, containerURL, filePath) {

    filePath = path.resolve(filePath);

    const fileName = path.basename(filePath);
    const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, fileName);

    return await uploadFileToBlockBlob(aborter, filePath, blockBlobURL);
}

async function uploadStream(aborter, containerURL, filePath) {

    filePath = path.resolve(filePath);

    const fileName = path.basename(filePath).replace('.md', '-stream.md');
    const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, fileName);

    const stream = fs.createReadStream(filePath, {
      highWaterMark: FOUR_MEGABYTES,
    });

    const uploadOptions = {
        bufferSize: FOUR_MEGABYTES,
        maxBuffers: 5,
    };

    return await uploadStreamToBlockBlob(
                    aborter, 
                    stream, 
                    blockBlobURL, 
                    uploadOptions.bufferSize, 
                    uploadOptions.maxBuffers);
}

I tried both uploadLocalFile and uploadStream I comment 1 of them out and try the other by itself, not sure which is the correct one to use for images.

If I go to the blockBlobURL I get error: This XML file does not appear to have any style information associated with it. The document tree is shown below.

And also when I console.log the blob content I get: Downloaded blob content: "�PNG → with this weird ? before the PNG and the arrow after it.

Here is the output: enter image description here

So I am not sure what I am doing wrong, I think I am uploading correctly (not sure if I should be using uploadLocalFile or uploadLocalStream though but I think the upload is working succesfully), what am I doing wrong with the download though, the truth is I personaly wont be downloading the files just doing it to make sure it works, the other program that connects to the db will download the file. Also if you see the link for the blob after a0008 has /./ and when I place that link in the browser it removes that part, I dont know what that part /./ signifies.

Thank You

Upvotes: 1

Views: 1072

Answers (1)

Peter Pan
Peter Pan

Reputation: 24138

The blob url is consist of the host of your Azure Blob Storage account, container name and blob name. For example, the blob url https://facerstorage.blob.core.windows.net/a00008/./sun.png includes the container name a00008 and the blob name ./sun.png.

According to your code, the weird blob name ./sun.png is generated by the code below.

# In function uploadLocalFile
const fileName = path.basename(filePath);
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, fileName);

# In function uploadStream
const fileName = path.basename(filePath).replace('.md', '-stream.md');
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, fileName);

To fix it, you just need to check the value of fileName variable above to ensure it what you want.

As I known, your codes come from the offical document Quickstart: Upload, download, list, and delete blobs using Azure Storage v10 SDK for JavaScript (preview), which used the preview version of Storage SDK for Node v10 via npm i @azure/storage-blob.

There is another version of Storage SDK for Node v2 which can be installed via npm install azure-storage, you can refer to the README document of GitHub repo Azure/azure-storage-node.

The related code is simple in v2 version.

var azure = require('azure-storage');
var accountName = '<your account name>';
var accountKey = '<your account key>';
var blobService = azure.createBlobService(accountName, accountKey);
var containerName = '<your container name>';
blobService.createContainerIfNotExists(containerName, {
  publicAccessLevel: 'blob'
}, function(error, result, response) {
  if (!error) {
    // if result = true, container was created.
    // if result = false, container already existed.
  }
});

var blobName = '<your blob name, such as sun.png>';
var localFile = '<your local file, such as ./sun.jpg>';
blobService.createBlockBlobFromLocalFile(containerName, blobName, localFile, function(error, result, response) {
  if (!error) {
    // file uploaded
  }
});

I see you post another SO thread Need help downloading image from Azure Blobs using NodeJS using SDK v10, but I think the v2 SDK APIs are simple for you now.

Upvotes: 1

Related Questions