I'm building a web application using react and express. It takes multiple text files as an input, reformats them on the backend, stores all of them into a zip file on the backend and then I try to download this zip file from the react frontend. Whenever i click the download link on the frontend for the zip, i download the file but somethings gone wrong meaning i can't unzip it, error message : unable to expand fileName.zip. It is in an unsupported format. But if i just try and open it directly from my computer on the server, it opens fine.
Here are the main pieces of code being used and the different approaches i've tried. My project structure has the client and server side stored in two different folders.
Here is the code which manages the file input with react :
import UploadedFile from "./UploadedFile";
import { useState } from "react";
function FileContainer() {
const [files, setFiles] = useState([]);
const [event, setEvent] = useState();
const [isUploaded, setIsUploaded] = useState(false);
const [newZipPath, setNewZipPath] = useState('');
const getFileNames = (e) => {
setEvent(e);
setFiles(Array.from(e.target.files));
}
const removeFile = (fileToRemove) => {
const filesDataTransfer = new DataTransfer(); //creates a new datatransfew since you cant make a filelist
const filteredFiles = files.filter((file) => file.name !== fileToRemove);
setFiles(filteredFiles);
for (let i = 0; i < filteredFiles.length; i++) {
filesDataTransfer.items.add(filteredFiles[i]); //adds all the files to the datatransfer
}
event.target.files = filesDataTransfer.files; //updates the actual files being inputted
}
const uploadFile = async () => {
const filesForm = document.getElementById("fileInput").files;
const formData = new FormData();
for (let i = 0; i < filesForm.length; i++) {
formData.append("files", filesForm[i]);
}
console.log(filesForm.length);
if (filesForm.length !== 0) {
const response = await fetch('/api/test', {
method: 'POST',
body: formData
});
const data = await response.json();
setNewZipPath(data.zipPath); //setting the zip path used in the download link
}
setIsUploaded(true);
}
return(
<div className="centerFileUpload">
<div className="fileContainer">
<h1>Upload</h1>
<div className="fileUpload">
<img src="" alt="" />
<input type="file" id="fileInput" onChange={getFileNames} multiple required/>
<label htmlFor="fileInput" id="fileInputButton">Choose Files </label>
<p>Upload your podcast transcripts here</p>
</div>
<div className="selectedFiles">
{files.map((file, index) => <UploadedFile key={index} fileName={file.name} removeFiles={() => removeFile(file.name)}/>)}
</div>
<button id="file-upload-button" onClick={uploadFile}>Upload</button>
{isUploaded && <a href={newZipPath} download="zipFile.zip">Download Zip Here</a>} //creating the download link with the previously set zip path
</div>
</div>
);
}
export default FileContainer;
Here is the express server code :
const express = require('express');
const multer = require('multer');
const fs = require('fs').promises;
const JSZip = require('jszip');
const reformatFile = require('./reformat.js');
const app = express();
port = 5123;
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, __dirname + '/uploads/');
},
filename: (req, file, cb) => {
cb(null, 'new_' + file.originalname);
}
})
const upload = multer({storage: storage});
app.post('/api/test',upload.any(), async (req, res) => {
const jszip = new JSZip();
for (let i = 0; i < req.files.length; i++) {
let filePath = __dirname + '/uploads/' + req.files[i].filename;
await reformatFile(filePath, filePath);
const data = await fs.readFile(filePath, 'utf8');
jszip.file(req.files[i].filename, data);
}
const content = await jszip.generateAsync({ type: 'nodebuffer' });
await fs.writeFile(__dirname + '/uploads/newzip.zip', content);
res.json({'zipPath':__dirname + '/uploads/newzip.zip'});
});
app.listen(port, () => {
console.log('server running on ' + port);
});
In these approaches i just used absolute file paths. In the next approach i tried to serve the zip file statically and using a relative path, resulting in the same error when trying to open the downloaded file. These are the changes I tried :
app.use(express.static(__dirname + '/uploads/')); I then changed the res.json to res.json({'zipPath':'newzip.zip'});
I'm new to react and express so any help is appreciated with this problem or any other best practices I've missed in the code sections, thanks.