Node corrupting images during upload

I've been facing an issue with corrupted images when uploading them via Next.js API routes using Formidable.

When submitting a form from my React component, I'm utilizing the following functions:

    const fileUpload = async (file: File) => {
        const url = '/api/image'
        const formData = new FormData()
        formData.append('file', file)
        const config = {
            headers: {
                'content-type': 'multipart/form-data',
            },
        }
        const response = await axios.post(url, formData, config)
        const { data } = response
        return data
    }

    const handleSubmit = async (event: React.SyntheticEvent) => {
        const url = '/api/post'
        if (files) {
                        // ignore 
            fileUpload(files[0]).then((response) =>
                console.log('submit response', response)
            )
        }
        event.preventDefault()
    }

The structure of the API route in Next.js is as follows:

import formidable from 'formidable'
const fs = require('fs')
const { BlobServiceClient } = require('@azure/storage-blob')

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}

const AZURE_STORAGE_CONNECTION_STRING =
    process.env.AZURE_STORAGE_CONNECTION_STRING

export const config = {
    api: {
        bodyParser: false,
    },
}

const getBlobName = (originalName) => {
    const identifier = Math.random().toString().replace(/0\./, '')
    return `${identifier}-${originalName}`
}

export default async (req, res) => {
    const form = new formidable.IncomingForm()
    form.keepExtensions = true
    form.uploadDir = './public/static/uploads'

    form.parse(req, async (err, fields, files) => {
        if (err) {
            return
        }
        return res.json({ fields, files })
    })

    form.on('file', async (name, file) => {
        const blobServiceClient = await BlobServiceClient.fromConnectionString(
            AZURE_STORAGE_CONNECTION_STRING
        )
        const containerClient = await blobServiceClient.getContainerClient(
            'images'
        )
        const buff = fs.readFileSync(file.path)
        const data = buff.toString('base64')

        const blobName = getBlobName(file.name)
        const blockBlobClient = containerClient.getBlockBlobClient(blobName)

        blockBlobClient.upload(data, data.length)
    })
}

Upon inspection, the image stored locally appears to be corrupted and resembles a TV screen showing static. It seems like there might be an issue with how I am encoding it — Could it be related to ContentType or string encoding?

Answer №1

It seems like the issue arises from converting the data into a base64 encoded string:

const data = buff.toString('base64')

Since the uploaded file is already being saved somewhere on the server (accomplished by using the formidable package), consider trying something like this:

    const blobName = getBlobName(file.name)
    const blockBlobClient = containerClient.getBlockBlobClient(blobName)
    blockBlobClient.uploadFile(file.path)

Reference for the uploadFile() method: https://learn.microsoft.com/en-gb/javascript/api/@azure/storage-blob/blockblobclient?view=azure-node-latest#uploadfile-string--blockblobparalleluploadoptions-.

UPDATE

Please try out this code snippet. I tested it and successfully uploaded a file without any corruption issues.

  form.on('file', async (name, file) => {
    const blobServiceClient = await BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
    const containerClient = await blobServiceClient.getContainerClient('images');
    const blobName = file.name;
    const contentType = file.type;
    const filePath = file.path;
    const blockBlobClient = containerClient.getBlockBlobClient(blobName);
    const uploadBlobResponse = await blockBlobClient.uploadFile(file.path);
  });

UPDATE #2

Here's my complete code implementation:

<form id="form1" method="post" action="/upload" enctype="multipart/form-data">
  <input name="file" type="file" id="file1" accept="image/*"/>
  <input type="button" id="button1" value="Upload" />
</form>


<script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>

<script>
  $(document).on('ready', function() {

  });
  $('#button1').on('click', function(e) {
    data = new FormData();
    console.log($('#file1')[0].files[0]);
    data.append('file', $('#file1')[0].files[0]);
    console.log(data);
    $.ajax({
            url: '/upload',
            data: data,
            processData: false,
            contentType: false,
            type: 'POST',
            success: function ( data ) {
                alert( data );
            }
        });
    e.preventDefault();
    e.stopPropagation();
  });
</script>

var express = require('express'),
    path = require('path'),
    fs = require('fs'),
    formidable = require('formidable');
const { BlobServiceClient } = require('@azure/storage-blob');

var app = express();

app.set('port', (process.env.PORT || 5000));

// Configure express to serve static files from specific directories
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));

app.listen(app.get('port'), function() {
    console.log('Express started at port ' + app.get('port'));
});

app.get('/', function (req, res) {
    res.sendFile(path.join(__dirname, 'index.html'));
});


app.post('/upload', function(req, res) {
  const connectionString = 'DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key;EndpointSuffix=core.windows.net;';
  const container = 'container-name';

  let form = new formidable.IncomingForm();
  form.keepExtensions = true;
  form.uploadDir = './public/static/uploads';
  form.parse(req, async function (err, fields, files) {
  });

  form.on('file', async (name, file) => {
    const blobServiceClient = await BlobServiceClient.fromConnectionString(connectionString);
    const containerClient = await blobServiceClient.getContainerClient(container);
    const blobName = file.name;
    const contentType = file.type;
    const filePath = file.path;
    console.log(file);
    const blockBlobClient = containerClient.getBlockBlobClient(blobName);
    const uploadBlobResponse = await blockBlobClient.uploadFile(file.path);
    console.log(uploadBlobResponse);
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Response Looping Function

I am struggling with looping and storing data in an array. /** Model for displaying response*/ export class ResultsData { id: number, name: string, startDate: string, endDarte: string, startTime: string, ...

What is the proper method for setting up handlers in functional React components?

My knowledge of JavaScript tells me that there are three different ways to define functions. Let's take a look at them: 1. Declaration function handleEvent(e) {} 2. Assignment var handleEvent = function(e) {} 3. Arrow var handleEvent = (e) => ...

NodeJS tool for interacting with a simulated DOM and coordinating updates with a web browser

I'm currently in the process of developing a nodejs application and I'm keen on manipulating a virtual representation of the DOM on the server side, then syncing these modifications to a connected browser in real-time. While I'm aware of li ...

Updating a single .jshintrc option for a folder

My project has a .jshintrc file at the root, containing the following settings: { "node": true, "smarttabs": true, "undef": true, "unused": true } While these settings work well for node-related code in my project, they are not suitable for brows ...

Utilize the up and down arrow keys to scroll through a description list in React

If you want to navigate through the list of Description Details using the tab and shift tab keys, it can be done easily. The default behavior allows for smooth navigation. <dl> <dt style={{ textAlign: "center" }}>Beast of Bodmin< ...

When attempting to retrieve information using the findById(''), the process became frozen

When attempting to retrieve data using findById(), I'm encountering a problem. If I provide a correct ObjectID, the data is returned successfully. However, if I use an invalid ObjectID or an empty string, it gets stuck. If findById() is called with a ...

Achieving selective exclusion of specific keys/values while iterating through an array and rendering them on a table using Angular

Currently facing a hurdle and seeking advice I am developing an angular application that fetches data from an API and presents it on the page The service I am utilizing is named "Api Service" which uses HTTPClient to make API calls apiservice.service.ts ...

Utilize app.js variables within routes without relying on global express

My configuration in app.js looks like this: const express = require('express') , routes = require('./routes') , user = require('./routes/user') , http = require('http') , path = require('path') , Server = ...

Instead of watching the video player, the puppeteer automatically downloads the video file

So I have this code snippet below: ;(async () => { const browser = await puppeteer.launch({ args: ['--no-sandbox'], headless: false }) const page = await browser.newPage() await page.goto('https://www.w3schools.com/html ...

Error in communication: Microsoft Bot framework encountered an issue with receiving a security token during the ChatConnector process

My Node.js bot framework version is 3.3.3 and I have successfully configured the "Skype" channel. However, when trying to set up the "Facebook Messenger" channel, I encounter an error stating "No security token sent". I am currently using ngrok for testing ...

When attempting to transfer data from a client to a server, a "Bad Request" error is encountered with the message: `POST http://localhost:5000/api

Hey everyone, I'm facing an issue with sending user data from the client-side to the server-side. Whenever I try to send new user details to the server, I encounter the following error: An alert pops up with the message "Enter valid credentials" and ...

Using NPM version 7 to pass flags to a script is a convenient feature

Previously in NPM versions before 7, it was possible to pass custom flags to a package.json script using dollar-asterisk: // package.json "scripts": { "build": "npx pkg-bin build $*" } For instance, running the above script ...

A guide on setting up fixed row numbers in MUI-X DataGrid

One challenge I am facing is rendering the row numbers in a table so that they remain static even when columns are sorted or filtered. I attempted to use the getRowIndexRelativeToVisibleRows method of the grid API, but unfortunately, it does not work as ex ...

Updating a label dynamically in Angular

QUESTION: Is there a way to dynamically change the text of a label based on a certain condition? Specifically, I want the label to be blank when I'm on a specific route in my App. CURRENT APPROACH: <RadSideDrawer allowEdgeSwipe=&quo ...

Trouble with defining variables in EJS

Recently delving into the world of node development, I encountered an issue with my EJS template not rendering basic data. I have two controllers - one for general pages like home/about/contact and another specifically for posts. When navigating to /posts ...

In React Native on Android, the permission to WRITE_EXTERNAL_STORAGE is consistently denied

Application Environment Information: "react": "18.2.0", "react-native": "0.71.7", "react-native-permissions": "^3.8.0", "react-native-webview": "^12.0.2" Testing Device Detail ...

The reducer I have is inexplicably returning undefined even though I'm certain it was added to combineReducers

After countless hours of debugging, everything seems to be in working order but the problem still persists. The main reducer file is located at reducers/index.js // @flow import { combineReducers } from "redux"; import blocks from "./blocks"; import user ...

The error message "Cannot bind to 'ngForOf' because it is not recognized as a valid property of the element."

After utilizing NGFor for quite some time, I encountered an unexpected issue in a new application where I received the error message: Can't bind to 'ngForOf' since it isn't a known property of 'div'.' I found it strang ...

Tips for obtaining an array of JSON objects instead of Mongoose documents

When executing the .find operation like this: Collection.find({name: 'Erik'}, function (err, docs) { // do something }); The 'docs' variable contains an array of fully functional mongoose documents. However, I need to obtain an arra ...

Knejx Js is the embodiment of guarantees

I am trying to figure out how to make this function work. I only receive a promise as the output. codeProducts.forEach((code, index) => { const qt = app.db('products').where('code', code).first().then(result => result.quanti ...