I am working on my first ever MERN stack web app. I have used multer on my Node Js backend to upload files from my React frontend. I have been storing the files in the uploads folder which is outside of the frontend folder. I have been saving the image path in my MongoDB database. The idea was to use the image path to insert the image into my React frontend. The path stored in MongoDB is correct and images are also added in the uploads folder but they are not sowing on the frontend. I am actually storing paths of three images in an array using the same function. Below is my code
the image uploading function
const handleImageupload = async (event, Img1, Img2, Img3) => {
const file = event.target.files[0];
const formData = new FormData();
formData.append("image", file);
try {
setUploadLoading(true);
setUploadError(null);
const config = {
headers: {
"Content-type": "multipart/form-data",
// Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.post(
"http://localhost:5000/api/uploads/image",
formData,
config
);
if (Img1) {
setImage1(data.fileName);
}
if (Img2) {
setImage2(data.fileName);
}
if (Img3) {
setImage3(data.fileName);
}
setUploadLoading(false);
} catch (error) {
const errorMessage = error.response
? error.response.data.message
: error.message;
setUploadLoading(false);
setUploadError(errorMessage);
}
};
backend route of uploads
import express from "express";
import multer from "multer";
const router = express.Router();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
const fileName =
file.fieldname + "-" + uniqueSuffix + path.extname(file.originalname);
cb(null, fileName);
},
});
const checkFileType = function (file, cb) {
const types = /jpg|png|jpeg/;
console.log(file.fieldname, file.fileName);
const isValidType = types.test(path.extname(file.originalname).toLowerCase());
const isValidMime = types.test(file.mimetype);
if (isValidType && isValidMime) {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: storage,
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
},
});
router.post("/image", upload.single("image"), function (req, res) {
console.log(req.file);
res.json({ fileName: `/uploads/${req.file.filename}` });
});
export default router;
server.js
import dotenv from "dotenv";
import path from "path";
import colors from "colors";
import cors from "cors";
import { errorHandler, notFoundHandler } from "../middlewares/errorHandler.js";
import ConnectDb from "../config/db.js";
import laptopRoutes from "../routes/laptops.js";
import userRoutes from "../routes/userRoutes.js";
import uploadRoutes from "../routes/uploads.js";
import imagesRoutes from "../routes/images.js";
import orderRoutes from "../routes/order.js";
dotenv.config();
ConnectDb();
const app = express();
app.use(cors());
app.use(express.json());
app.get("/check", (req, res) => {
res.json({ message: "Api was called" });
});
app.use("/api/products", laptopRoutes);
app.use("/api/users", userRoutes);
app.use("/api/orders", orderRoutes);
app.use("/api/carouselimages", imagesRoutes);
app.use("/api/uploads", uploadRoutes);
const __dirname = path.resolve();
app.use("/uploads", express.static(path.join(__dirname, "/uploads")));
app.use(notFoundHandler);
app.use(errorHandler);
const port = process.env.PORT | 5000;
const mode = process.env.MODE;
app.listen(port, () => {
console.log(
`Application is running at port no ${port} in ${mode} mode`.inverse.cyan
);
});
Related
I'm using Multer on server side for file upload
Midleware :
const util = require("util");
const path = require("path");
const multer = require("multer");
var storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, path.join(`${__dirname}../../upload`));
},
filename: (req, file, callback) => {
const match = ["image/png", "image/jpeg"];
if (match.indexOf(file.mimetype) === -1) {
var message = `<strong>${file.originalname}</strong> is invalid. Only accept png/jpeg.`;
return callback(message, null);
}
var filename = `${Date.now()}-bezkoder-${file.originalname}`;
callback(null, filename);
}
});
var uploadFiles = multer({ storage: storage }).array("files", 10);
var uploadFilesMiddleware = util.promisify(uploadFiles);
module.exports = uploadFilesMiddleware;
Controller
const multipleUpload = async (req, res) => {
try {
await upload(req, res);
console.log('Check logs file ', req.Content - Type);
if (req.files.length <= 0) {
return res.send(`You must select at least 1 file.`);
}
return res.send(`Files has been uploaded.`);
} catch (error) {
console.log(error);
if (error.code === "LIMIT_UNEXPECTED_FILE") {
return res.send("Too many files to upload.");
}
return res.send(`Error when trying upload many files: ${error}`);
}
};
module.exports = {
multipleUpload: multipleUpload
};
Client capture Payload
My problem in upload event the server side show error messenger
Please help me to solve it.
Thanks
I have tried upload by axios is not problem but
I'm using the tool react Devextreme --> FileUploader . The supporter of devextreme did n't support server side .
In react hooks web app, how can we receive a csv file in the server side. The below is not working as I am getting the file undefined in server side. Could someone please advise ?
server.js
const multer = require('multer');
const bodyParser = require("body-parser");
const path = require('path');
app.use(express.static(path.join(__dirname, 'public')));
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/csv')
},
filename: function (req, file, cb) {
var ext = file.originalname.split('.').pop();
cb(null, file.fieldname + '-' + Date.now() + '.' + ext);
}
})
var upload = multer({ storage: storage });
app.put('/service/managenominees', upload.single('file'), async (req, res, next) => {
// csv file has two columns named Name, Email, I would like to receive value from those..
const data = req.file;
try {
if(req.body.file){
var name = req.file.Name;
var email = req.file.Email;
}
var nomineeData = {userName: name, userEmail: email};
res.status(200).send(nomineeData);
} catch (e) {
res.status(500).json({ fail: e.message });
}
});
manageNominee.js
import React, { useRef, useEffect, useState } from "react";
import Axios from "axios";
const ManageNominees = () => {
const [uploadFile, setUploadFile] = React.useState();
const [csvData, setCsvData] = useState([]);
const onChangeCsv = (e) => {
setCsvData(e.target.files[0]);
}
const submitForm = (data) => {
const dataArray = new FormData();
dataArray.append("uploadFile", data);
Axios.put("http://localhost:8000/service/managenominees", dataArray, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((response) => {
// successfully uploaded response
})
.catch((error) => {
// error response
});
};
return (
<div>
<form onSubmit={submitForm} encType="multipart/form-data">
<h1>Upload Data</h1>
<input type="file" name="csvfile" onChange={onChangeCsv}/>
<button>Submit</button>
</form>
</div>
)
}
export default ManageNominees
There are two issues:
HTML attribute and the mutler upload option are different.
File values cant be accessed directly either convert the buffer and read the content or read the file (below code reads the file).
const multer = require('multer');
const bodyParser = require("body-parser");
const path = require('path');
const csv = require('csv-parser');
const fs = require('fs');
...
app.put('/service/managenominees', upload.single('csvfile'), (req, res, next) => {
console.log(req.file);
fs.createReadStream(req.file.path)
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => {
console.log(results);
// Result would be array as its CSV, iterate over the array and to get username and email id.
res.status(200).send(results);
});
});
Note: Code does not handle if the file does not exist.
I would like to open in React a PDF file in a new tab when the URL is
blob:http://localhost:300/sample.pdf
Currently, it opens PDF file in a new tab, but the URL is
blob:http://localhost:3001/cfd3b31b-b4a8-4c65-aead-694fd27f12a8
My goal is to set the name to the pdf file in the URL (not download file)
What should be changed in the code in order to add the file name in the URL?
Code in React.js
import axios from "axios";
const ShowPDF = () => {
const getPdfFileAsBlob = async () => {
const url = `http://localhost:5001/pdf`;
//Force to receive data in a Blob Format
const config: any = {
responseType: "blob",
};
try {
const response = await axios.get(url, config);
//Create a Blob from the PDF Stream
const file = new Blob([response.data], {
type: "application/pdf",
});
//Build a URL from the file
const fileURL = URL.createObjectURL(file);
//Open the URL on new Window
window.open(fileURL);
} catch (error) {
console.log(error);
}
};
return <button onClick={getPdfFileAsBlob}>Show PDF</button>;
};
export default ShowPDF;
Code in Node.js - server.jsconst fs = require("fs");
const express = require("express");
const cors = require("cors");
const excel = require("exceljs");
const app = express();
app.use(cors());
app.use(express.json());
// GET
// Pdf route that will serve pdf
app.get("/pdf", (req, res) => {
const file = fs.createReadStream("./public/samplePDF.pdf");
file.pipe(res);
});
const PORT = process.env.PORT || 5001;
app.listen(PORT, () => {
console.log(`Server Started on Port ${PORT}`);
});
Multer adds the uploaded files to req.file or req.files. My code works in Chrome as expected, but both req.file and req.files are empty in both Firefox (68.01) and Edge (44.17763.1.0).
Why does the request object doesn't contain the files in Firefox and Edge?
My multer config:
const path = require('path');
const uuidv4 = require('uuid/v4');
const multer = require('multer');
const projectRoot = require('./projectRoot');
// Allowed audio mime types
const audioMimeTypeToExt = {
'audio/wav': '.wav',
'audio/mp3': '.mp3',
};
// Allowed image mime types
const imageMimeTypeToExt = {
'image/jpeg': '.jpg',
'image/png': '.png'
};
// Storage options
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(projectRoot.path, '/public/tracks/'))
},
filename: function (req, file, cb) {
if (file) {
// New file name is uuid + extension (i.e. '10ba038e-48da-487b-96e8-8d3b99b6d18a.mp3')
cb(null, uuidv4() + audioMimeTypeToExt[file.mimetype])
} else {
console.log('File missing.');
}
}
});
// Filter options
const filter = function (req, file, cb) {
if (!(file.mimetype.toLowerCase() in audioMimeTypeToExt)) {
// Reject upload
cb(null, false);
}
// Accept upload
cb(null, true);
};
const uploadMiddleware = (req, res, next) => {
multer(
{
storage: storage,
fileFilter: filter,
limits: {fileSize: 50000000} //50mb
}
).array('tracks', 10)(req, res, function (err) {
if (err && err.code === "LIMIT_FILE_SIZE") {
return res.status(413).send(err.message);
}
next();
});
};
module.exports = {
audioMimeTypeToExt,
imageMimeTypeToExt,
uploadMiddleware: uploadMiddleware,
};
My route
const express = require('express');
const router = express.Router();
const sessionMiddleware = require('../middlewares/sessionMiddleware');
const {uploadMiddleware} = require('../config/multerConfig');
const uploadController = require('../controllers/uploadController');
router.post('/',
sessionMiddleware.requiredLogin,
uploadMiddleware,
uploadController.upload_post
);
module.exports = router;
My controller
const {processUploads} = require('../utilities/uploadsProcessor');
exports.upload_post = async function (req, res, next) {
if (req.files && req.files.length) { // req.files empty in Firefox and Edge
await processUploads(req);
console.log('Upload successful.');
res.status(200).end();
}
else {
res.status(404).end();
}
};
Thank you
Figured out what was going wrong. Firefox and Edge have different values in the file.mimetype field. For MP3 files, Chrome adds 'audio/mp3', while Firefox and Edge add 'audio/mpeg'. So my filter was filtering our files that don't contain 'audio/mp3' or 'audio/wav' mimetypes.
I have a react redux app where I am posting data to my node (express) server. In my action creator the data is being sent to the server but it isn't responding to the file. Here's my action creator.
// action creator
export function addItem(product) {
return dispatch => {
dispatch(request(product));
axios.post(api + '/api/addtoinventory', { product })
.then(res => {
dispatch(success(product));
})
.catch(err => {
dispatch(failure(err.toString()));
});
}
function request(product) { return { type: ADDING_ITEM, product } }
function success(product) { return { type: ITEM_ADDED, product } }
function failure(error) { return { type: ADD_TOAST, payload: error} }
}
Then in my express file I have code like this..
// server.js
var express = require('express');
var router = express.Router();
var multer = require('multer');
var uuidv4 = require('uuid/v4');
var path = require('path');
var database = require('./database');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '../../../adminpanel/src/0000001');
},
filename: (req, file, cb) => {
const newFilename = `${uuidv4()}${path.extname(file.originalname)}`;
cb(null, newFilename);
}
});
const upload = multer({ storage });
router.post('/', function(req, res) {
var title = req.body.product.title;
var price = req.body.product.price;
var description = req.body.product.description;
database.query("INSERT INTO `Items` (`ID`, `Title`, `Price`, `Description`, `CreateDate`) VALUES (NULL, ?, ?, ?, CURRENT_TIMESTAMP)", [title, price, description], function(err, result) {
if(err) {
console.log(err);
} else {
var id = result.insertId;
console.log(id);
}
});
});
module.exports = router;
Then when i check for the console log I just get this in return
OPTIONS /api/addtoinventory 200 10.300 ms - 4
Shouldn't that say POST instead of OPTIONS ?
You need to create a middleware which will allow CORS for your registered req origins
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'your domain here');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
Then in your startup file include this middleware
app.use(allowCrossDomain);
If you want to read about it more
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests