Docker and Multer upload volumes ENOENT error - javascript

first question + junior dev here !
So my problem is : I'm developping an API whith nodejs/express + Docker and Multer where I want to upload files.
I tried to configure Docker as good as I can, same for Multer and persist uploaded files in a volume but it keeps throwing me this error :
{
"errno": -13,
"code": "EACCES",
"syscall": "open",
"path": "public/media/pictures/picture-1642414319690.jpg",
"storageErrors": []
}
Here is my Multer upload middleware config :
const multer = require('multer');
const path = require('path');
// PICTURES
// Picture storage path
const storage = multer.diskStorage({
destination(req, file, cb) {
cb(null, '/public/media/pictures');
},
filename: (req, file, cb) => {
cb(
null,
`${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`
);
},
});
// Check pictures type
const checkPicType = (file, cb) => {
// Allowed ext
const pictypes = /jpeg|jpg|png/;
// Check ext
const extname = pictypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = pictypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
}
return cb('Error: Images only!');
};
// Picture upload options
const picUpload = multer({
storage,
limits: {
fields: 5,
fieldNameSize: 10,
fieldSize: 2000,
fileSize: 25000000,
},
fileFilter(req, file, cb) {
checkPicType(file, cb);
},
}).single('picture');
module.exports = {
picUpload,
};
My Upload method in api/picture.js :
router.post('/upload', (req, res) => {
picUpload(req, res, (err) => {
if (err) {
return res.status(403).json(err);
}
return res.status(201).json({
path: `${req.protocol}://${req.hostname}:${PORT}/${req.file.path}`,
});
});
});
and finally my docker-compose :
services:
web:
build:
context: ./
target: dev
volumes:
- .:/src
- uploaded-files:/src/public/media/files
- uploaded-pictures:/src/public/media/pictures
command: npm run start:dev
ports:
- "5000:5000"
environment:
NODE_ENV: development
DEBUG: nodejs-docker-express:*
postgres:
image: postgres
restart: always
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASS}
volumes:
- postgres:/var/lib/postgresql/data
ports:
- '5432:5432'
volumes:
postgres:
uploaded-files:
uploaded-pictures:
As I said I'm pretty to docker and multer so if I missed a file or some lines to help you understand better, tell me.
Thanks!

I figured it out, it was just a simple path arror in the middleware (picUpload.js)
cb(null, '/src/public/media/pictures');
// Picture storage path
const storage = multer.diskStorage({
destination(req, file, cb) {
cb(null, '/src/public/media/pictures');
},
filename: (req, file, cb) => {
cb(
null,
`${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`
);
},
});

Related

Error 500 when trying to upload to AWS S3 with multer-s3

I am using express + multer-S3 to upload files to AWS S3. Using the following code, I get an internal server error 500 and I don't understand what I am doing wrong.
const aws = require("aws-sdk");
console.log("Require AWS");
const multer = require("multer");
const multerS3 = require("multer-s3");
const s3 = new aws.S3();
aws.config.update({
secretAccessKey: process.env.S3_ACCESS_SECRET,
accessKeyId: process.env.S3_ACCESS_KEY,
region: "eu-west-3",
});
const fileFilter = (req, file, cb) => {
if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
cb(null, true);
} else {
cb(new Error("Invalid file type, only JPEG and PNG is allowed!"), false);
}
};
const upload = multer({
fileFilter,
storage: multerS3({
acl: "public-read",
s3: s3,
bucket: "schubox",
contentType: multerS3.AUTO_CONTENT_TYPE,
metadata: function (req, file, cb) {
console.log("Called when saving image to AWS");
cb(null, { fieldName: "TESTING_METADATA" });
},
key: function (req, file, cb) {
console.log("FILE ==> " + JSON.stringify(file));
cb(null, Date.now().toString());
},
}),
});
And in my route
router
.route("/rayons")
.get(auth, ctrlRayons.rayonsListe)
.post(auth, **upload.single("fichier")**, ctrlRayons.rayonsCreerUn);
I get this error
Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1"
Error: connect EHOSTDOWN 169.254.169.254:80 - Local (192.168.1.10:56879) at internalConnect (net.js:934:16) at defaultTriggerAsyncIdScope (internal/async_hooks.js:452:18) at net.js:1022:9 at processTicksAndRejections (internal/process/task_queues.js:77:11)
What am I doing wrong?
My AWS S3 account is ok, I have my Id and my secret ok, but nothing is written in my bucket. All the tutorials show the same procedure as the one I use.
Thanks again for your help.

Why am I getting "ENOENT: no such file or directory, open" when trying to save an image through multer's storage?

I'm trying to use multer to save an image to my back-end, and more specifically, to public/images/servers folder. Sadly I get an error:
[Error: ENOENT: no such file or directory, open 'C:\MAMP\htdocs\Chat Backend\public\images\servers\2020-08-07T12:33:31.556Z-aohan-chen-.jpg'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'C:\\MAMP\\htdocs\\Chat Backend\\public\\images\\servers\\2020-08-07T12:33:31.556Z-aohan-chen-.jpg',
storageErrors: []
}
I'm not sure why it says that there is no such file or directory when everything up until here exists - 'C:\MAMP\htdocs\Chat Backend\public\images\servers'. The only thing left is for multer to save the image in the servers folder.
var multer = require('multer');
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/images/servers')
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname)
}
})
var fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/png' || file.mimetype === 'image/jpg' || file.mimetype === 'image/jpeg') {
cb(null, true)
} else {
cb(null, false)
}
}
app.use(multer({ storage: storage, fileFilter: fileFilter }).single('image'));

“ENOENT: no such file or directory, open” when attempting to save an image through multer's storage. Symbols are not the issue

For some reason if I attempt to save an image through multer's storage, I get this error:
[Error: ENOENT: no such file or directory, open 'C:\MAMP\htdocs\Chat Backend\public\images\servers\1596819056816AFKay.jpg'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'C:\\MAMP\\htdocs\\Chat Backend\\public\\images\\servers\\1596819056816AFKay.jpg',
storageErrors: []
}
My multer setup looks like this:
var multer = require('multer');
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/images/servers')
},
filename: (req, file, cb) => {
cb(null, Date.now() + file.originalname)
}
})
var fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/png' || file.mimetype === 'image/jpg' || file.mimetype === 'image/jpeg') {
cb(null, true)
} else {
cb(null, false)
}
}
app.use(multer({ storage: storage, fileFilter: fileFilter }).single('image'));
If I were to not use storage and just stick to dest, it saves the image just fine.
app.use(multer({ dest: 'public/images/servers' }).single('image'));
I've checked a lot of similar questions but their problem is usually that the name of the image contains symbols which are not allowed, whereas that is not the case with me because I've tried the simplest names (just a string for example) and I still get the error. Why might this error be happening?
I was facing the same issue. I am on windows OS. This helped:
new Date().toISOString().replace(/:/g, '-') + file.originalname

How to download files using multer-sftp

I have this code, but surfing the web, i cannot found some way to download a file from the remote server. I'm able to upload the files in the remote server but I don't have any idea how download from there.
var storage = sftpStorage({
sftp: {
host: '171.16.....',
port: xxxx,
username: 'username',
password: 'xxxxxxxxxxxxxxxx'
},
destination: function(req, file, cb) {
cb(null, 'uploads')
},
filename: function(req, file, cb) {
cb(null, Date.now() + file.originalname)
}
});
var upload = multer({ storage: storage })
This is the route to upload the files: (Works great!)
router.post('/upload-image', upload.single('file'), listarController.uploadImage);
This is the route to download the files - locally: (Searching a method...)
router.get('/get-file/:file', listarController.getFile);
The method to download locally:
controller.getFile = (req, res) => {
var file = req.params.file;
var path_file = './uploads/' + file;
fs.exists(path_file, (exists) => {
if (exists) {
return res.sendFile(path.resolve(path_file))
} else {
return res.status(200).send({
message: "The image doesn't exist."
})
}
})
}
Some suggestion? Thanks in advance
I solved it with the following libraries:
1. multer-sftp: To upload the files.
2. ftp: To download and rename the files.

Multer trying to create a new folder when one already exists

I'm using Multer to manage image uploads, and when running my app on my local machine everything works perfectly. But now that I'm trying to deploy to Heroku I get this error in my application logs:
Unhandled rejection Error: EROFS: read-only file system, mkdir
'/public'
...which seems like it's trying to create a directory rather than using the existing one (like it does on my local machine)
This is my the code I'm using for Multer:
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/img/') },
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + file.originalname)
} })
var upload = multer({storage: storage})
router.post('/:propertyid', upload.single('img'), function(req, res) {
Property.update({
img: req.file.filename
}, {
where: {
id: req.params.propertyid,
}
}).then(updatedProperty => {
res.redirect('/admin/' + updatedProperty)
})
});
The public/img directory already exists and when testing it, it runs fine with correct filenames and end up in the correct place. Any help is appreciated! Thanks!
Heroku dynos have an ephemeral filesystem. This answer by Naaman Newbold, explains very well what that means.
TL;DR:
Dynos' filesystem shouldn't be used to store any permanent storage or data besides what is deployed. In order to do use a storage, AWS S3 can be used.
You can Use fs-extra to create folder it will sync and create folder like below in below code I am creating directory by user_id and uploading multiple images so i have used fs.mkdirsSync(path) in my code
let fs = require('fs-extra');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
fs.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})

Categories

Resources