How can I upload array of files using multer - javascript

Have been trying to upload multiple images with multer array upload but they are not displaying in my index page but using single.upload() is working fine and displaying the images .
/ Set The Storage Engine
destination: './public/upload',
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
// Init Upload
const upload = multer({
storage: storage,
limits:{
fileSize: 100000000
},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
});
// Check File Type
function checkFileType(file, cb){
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
Var upload = multer({storage: storage})
router.post("/", upload.array('image'),(req, res) => {
const newSell= new Sell({
year: req.body.year,
text: req.body.text,
image:'/upload/'+req.files
});
newSell.save().then(sell => res.json(sell));
}
);
module.exports = router;

Related

Uploading multiple files to multiple locations with Multer & Node.JS

I am trying to write an app using NodeJS and Express which will upload both a user avatar which is a single image (jpeg, png or webp) and 'legalDocs' which is essentially also a single file that can either be an image (jpeg, png or webp) or a pdf file. The avatar needs to be uploaded to ./resources/(userID)/userAvatar and the legal docs to ./resources/(userID)/legalDocs. Along with some other text info that will be posted along with the request as a multipart/form-data.
The userID is only generated after processing the text data posted.
Here's my current non-working code
APP.JS
//ENV
require("dotenv").config();
require("express-async-errors");
//EXPRESS
const express = require("express");
const server = express();
global.__basedir = __dirname;
//routes
const authRouter = require("./routes/authRoutes.js");
server.use(express.json());
server.use(express.urlencoded({extended: true}));
server.use(express.static("./public"));
server.use("/api/v0/auth", authRouter);
const port = process.env.PORT || 3000;
const start = async () => {
try {
server.listen(port, () => {
console.log(`--> Listening on port ${port}...`);
});
} catch (error) {
console.log(error);
console.log("Fatal error!");
}
}
start();
authRoutes.js:
const express = require("express");
const router = express.Router();
const {signupWithEmail} = require("../controllers/auth.js");
router.route("/signup").post(signupWithEmail);
module.exports = router;
../controllers/auth.js:
const multer = require("multer");
const processReq = require("../middleware/upload.js");
const signupWithEmail = async (req, res, next) => {
//Processing to get the ID happens here.
//For simplicity we can pretend like the ID is directly
//posted in a field with the name id.
const id = req.body.id;
console.log("id:");
console.log(id);
await processReq(id)(req, res, next);
res.status(200).send("done!");
}
upload.js
const multer = require("multer");
const errors = require("../errors");
const maxSize = 2 * 1024 * 1024;
const acceptableFileMIMETypes = ["image/jpeg", "image/png", "image/webp", "application/pdf"];
const userAvatarFilter = function (req, file, cb) {
if ((file.fieldname === "userAvatar" || file.fieldname === "legalDocs")
&& acceptableFileMIMETypes.includes(file.mimetype)
&& !(file.fieldname === "userAvatar" && file.mimetype === "application/pdf")) {
if (file.fieldname === "userAvatar") {
cb(null, true);
} else {
cb(null, false);
}
} else {
cb(new errors.BadRequestError("Both files are required, and must be JPEG, PNG, WEBP. Legal documents can also be PDF."));
}
}
const userlegalDocsFilter = function (req, file, cb) {
if ((file.fieldname === "userAvatar" || file.fieldname === "legalDocs")
&& acceptableFileMIMETypes.includes(file.mimetype)
&& !(file.fieldname === "userAvatar" && file.mimetype === "application/pdf")) {
if (file.fieldname === "userAvatar") {
cb(null, false);
} else {
cb(null, true);
}
} else {
cb(new errors.BadRequestError("Both files are required, and must be JPEG, PNG, WEBP. Legal documents can also be PDF."));
}
}
const uploadFunc = (id) => {
return (req, res, next) => {
const userAvatarStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, __basedir + `/resources/${id}/userAvatar`);
},
filename: (req, file, cb) => {
console.log("Uploaded avatar!");
console.log(file.originalname);
console.log(file);
cb(null, file.originalname);
}
});
const legalDocsStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, __basedir + `/resources/${id}/legalDocs`);
},
filename: (req, file, cb) => {
console.log("Uploaded legalDocs!");
console.log(file.originalname);
console.log(file);
cb(null, file.originalname);
}
});
const uploadAvatar = multer({
storage: userAvatarStorage,
limits: {
fileSize: maxSize,
files: 2
},
fileFilter: userAvatarFilter
}).any();
const uploadLegalDocs = multer({
storage: legalDocsStorage,
limits: {
fileSize: maxSize,
files: 2
},
fileFilter: userlegalDocsFilter
}).any();
uploadAvatar(req, res, next);
uploadLegalDocs(req, res, next);
next();
}
}
module.exports = uploadFunc;
The Problem
The first problem with my code is quite obvious, I cannot parse text data from the request unless it had been processed by multer (with the current code, console.logging the id shows that it's undefined), but I need the ID to be passed to multer in order to save the files to the correct directory. It seems like I need some way to process text only and generate the ID, then process the files.
The second problem is that, even if the ID is static - meaning that in ./controllers/auth.js the signupWithEmail function became:
const multer = require("multer");
const processReq = require("../middleware/upload.js");
const signupWithEmail = async (req, res, next) => {
const id = 1337;
console.log("id:");
console.log(id);
await processReq(id)(req, res, next);
res.status(200).send("done!");
}
I this is the output I get on the console when I try to post:
id:
1337
Uploaded legalDocs!
cours-analyse-numerique-ch1-21_22.pdf
{
fieldname: 'legalDocs',
originalname: 'cours-analyse-numerique-ch1-21_22.pdf',
encoding: '7bit',
mimetype: 'application/pdf'
}
node:_http_outgoing:771
throw new ERR_HTTP_HEADERS_SENT('remove');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot remove headers after they are sent to the client
at new NodeError (node:internal/errors:400:5)
at ServerResponse.removeHeader (node:_http_outgoing:771:11)
at write (C:\Users\der_u\source\repos\ATEEK\node_modules\finalhandler\index.js:282:9)
at AsyncResource.runInAsyncScope (node:async_hooks:204:9)
at listener (C:\Users\der_u\source\repos\ATEEK\node_modules\on-finished\index.js:170:15)
at onFinish (C:\Users\der_u\source\repos\ATEEK\node_modules\on-finished\index.js:101:5)
at callback (C:\Users\der_u\source\repos\ATEEK\node_modules\ee-first\index.js:55:10)
at IncomingMessage.onevent (C:\Users\der_u\source\repos\ATEEK\node_modules\ee-first\index.js:93:5)
at IncomingMessage.emit (node:events:513:28)
at endReadableNT (node:internal/streams/readable:1359:12) {
code: 'ERR_HTTP_HEADERS_SENT'
}
and only 'legalDocs' get uploaded.
Is there any way to solve these problems without using a temporary directory to save all the files then move them once the ID had been generated? And what does the [ERR_HTTP_HEADERS_SENT] error mean?

uploading two files from two fields with multer as middleware

i'm trying to upload two files with different file extensions with multer from two fields but when i try it with postman the result always for the file is null, what is the solution for my problem? here is my code
middleware/uploadEpub
const multer = require('multer')
exports.uploadEpub = (epubFile, coverFile) => {
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads")
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname.replace(/\s/g, ""))
}
})
const upload = multer({
storage
}).fields([{name: "bookFile", maxCount: 1},{name: "coverFile", maxCount: 1}])
}
controller/book
exports.addBook = async (req, res) => {
try {
const { ...data } = req.body
const newBook = await book.create({
...data,
bookFile: req.file,
coverFile: req.file
})
let bookData = await book.findOne({
where: {
id: newBook.id
},
attributes:{
exclude: ['createdAt','updatedAt']
}
})
bookData = JSON.parse(JSON.stringify(bookData))
res.send({
status: "Success",
Book: {
...bookData
}
})
} catch (error) {
console.log(error)
res.status(500).send({
status: "Failed",
message: "Server Error"
})
}
}
Multer set up
const multer = require('multer')
const path = require('path')
const { nanoid } = require('nanoid')
//Set Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: (req, file, callback) => {
const id = nanoid(6)
const newFilename = `${file.fieldname}_${id}-${new Date().toISOString().replace(/:/g, '-')}${path.extname(file.originalname)}`
callback(null, newFilename)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: 5572864 }, // up to 5.5 MB
fileFilter: (req, file, callback) => {
checkFileType(file, callback)
},
})
//Check File Type
const checkFileType = (file, cb) => {
//Allowed extensions
const fileType = /jpeg|jpg|png|gif|svg|pdf|epub/
//Check extension
const extname = fileType.test(path.extname(file.originalname).toLowerCase())
//Check mimetype
const mimetype = fileType.test(file.mimetype)
if (extname && mimetype) {
return cb(null, true)
} else {
return cb('Error: wrong file type!')
}
}
module.exports = upload
/***** middlewares.js *****/
module.exports.imageUploader = (req, res, next)=>{
const files = req.files
const uploadedFiles = []
for (var i = 0; i <images.length; i++){
uploadFiles.push('https://yourserver.com/public/uploads/' + files[i].filename)
}
req.uploadFiles = uploadFiles.toString() //appending files to req
next()
return
}
/**** index.js or app.js ****/ //where your routes are defined
router.post('/books/add', upload.array('images', 10), imageUploader, book.addBook) // allowing up to 10 files to be uploaded, calling imageUploader as a middleware
/*** Controllers/book ***/
exports.addBook = async (req, res) => {
const uploadedFiles = req.uploadFiles; //catching files from imageUploader middleware
// ... rest of your code
}
Try to upload the file as form-data in postman, and put the key with the same name that you have set in multer, the postman will look like this:
Try this:
const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
})

Multer doesn't save the file

Multer does not save the file and I cannot see any logs... The folder is empty, no any files.
The image data is actually sent to the server as its console logged:
Screenshot of req.files from log
What am I doing wrong? Please help me find
const express = require('express');
const router = express.Router();
const path = require('path');
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
console.log('destination') // can't see this log
cb(null, './uploads/');
},
filename: (req, file, cb) => {
console.log('filename') // can't see this log
const ext = file.mimetype.split("/")[1];
cb(null, Date.now() + path.extname(file.originalname));
}
});
const uploadImage = multer({
storage,
limits: { fieldSize: 1024 * 1024 },
fileFilter: (req, file, cb) => {
console.log('log!') // can't see this log
const ext = path.extname(file.originalname);
if (ext !== '.jpg' && ext !== '.jpeg' && ext !== '.png') {
console.log('not log!') // can't see this log
const err = new Error('Extention');
err.code = 'EXTENTION';
return cb(err);
}
console.log('log!') // can't see this log
cb(null, true);
}
}).single('photo');
router.post('/image', async (req, res) => {
console.log(req.files) // can see this log
uploadImage(req, res, err => {
console.log('upload') // can see this log
let error = '';
if (err) {
console.log(err)
if (err.code === 'LIMIT_FILE_SIZE') {
error = 'Max 500kb!';
}
if (err.code === 'EXTENTION') {
error = 'Only jpg and png!';
}
}
res.json({
ok: !error,
error
});
})
});
Multer finally gave an error, so the problem was resolved... The problem was that the names of these fields are different:
Server:
.single('pic');
And in the request to the server:
formData.append('pic', file);
The code seems to work fine for me but I just had to manually create the uploads directory.
I used postman to test this and the picture appeared in my uploads directory.
# Console Output
SERVER RUNNING ON 3000
undefined
log!
log!
destination
filename
upload

Node js getting name of the file being uploaded

var express = require("express");
var multer = require('multer');
const exec = require('child_process').exec;
var app = express();
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
});
var upload = multer({ storage : storage}).single('myfile');
debugger;
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
app.post('/uploadjavatpoint',function(req,res){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
console.log("Uploading "+res.files);
res.end("File is uploaded successfully!");
console.log("Coverting to PDF");
debugger;
exec('"./px-8-5-4-win-x86-64/sdk/demo/pxsample.exe" "./uploads/EM_spectrum.ppt" "./uploads/EM_spectrum.pdf"');
console.log("Coversion Done");
});
});
app.listen(2000,function(){
console.log("Server is running on port 2000");
});
I am sending the file using postman with file(myfile) embedded in the body. I want to get the original name of the file being uploaded. I am new to node js please help me how to get the original name of the file being uploaded.
I tried req.file.filename as well as req.files but they don't seem to work
this should help you
> const _files = req.files;
> for (const file of _files) {
> name = file.originalname;
> size = file.size;
> }
in postman,
Choose form-data in the body, file in the key and select the file in the value

How I can see my uploading images' names on console?

I am pretty new on using express and NodeJs, I have created a function named upload which upload images, the code as follow:
const fs = require("fs");
var UserId = 2;
var storage = multer.diskStorage({
destination: function (req, file, callback) {
var dir = "./public/images/uploads/";
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
dir = "./public/images/uploads/" + UserId;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
callback(null, dir);
},
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + Date.now() + ".jpg");
},
});
const maxSize = 1 * 1000 * 1000;
var upload = multer({
storage: storage,
limits: { fileSize: maxSize },
fileFilter: function (req, file, cb) {
// Set the filetypes, it is optional
var filetypes = /jpeg|jpg|png/;
var mimetype = filetypes.test(file.mimetype);
var extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb(
"Error: File upload only supports the " +
"following filetypes - " +
filetypes
);
},
}).array("mypic", 2);
I am trying to see the filename on console when POST happen, the POST code as follow:
app.post("/uploadProfilePicture", function (req, res, next) {
upload(req, res, function (err) {
if (err) {
res.send(err);
} else {
res.send("Success, Image uploaded!");
}
});
});
I am trying to do something like that: console.log(req.filename);
You are looking for req.files.FileFieldName where FileFieldName is name attribute of your file element in your html form.
if(req.files)
{
console.log(req.files.FormFieldName);
}

Categories